HEX
Server: Apache
System: Linux darrell.nocdirect.com 4.18.0-513.18.2.el8_9.x86_64 #1 SMP Sat Mar 30 06:10:41 EDT 2024 x86_64
User: joderbya (1358)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /home/joderbya/beira.quick-step-ei.com/imports/import.php
<?php
/* Copyright (C) 2005-2016 Laurent Destailleur  <eldy@users.sourceforge.net>
 * Copyright (C) 2005-2009 Regis Houssin        <regis.houssin@inodbox.com>
 * Copyright (C) 2012      Christophe Battarel	<christophe.battarel@altairis.fr>
 * Copyright (C) 2022      Charlene Benke		<charlene@patas-monkey.com>
 * Copyright (C) 2024-2025	MDW							<mdeweerd@users.noreply.github.com>
 * Copyright (C) 2024-2025  Frédéric France             <frederic.france@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

/**
 *      \file       htdocs/imports/import.php
 *      \ingroup    import
 *      \brief      Pages of import Wizard
 */

require_once '../main.inc.php';
/**
 * @var Conf $conf
 * @var DoliDB $db
 * @var HookManager $hookmanager
 * @var Translate $langs
 * @var User $user
 */
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/imports/class/import.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/modules/import/modules_import.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/import.lib.php';

// Load translation files required by the page
$langs->loadLangs(array('exports', 'compta', 'errors', 'projects', 'admin'));

// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
$hookmanager->initHooks(array('imports'));

// Security check
$result = restrictedArea($user, 'import');

// Map icons, array duplicated in export.php, was not synchronized, TODO put it somewhere only once
$entitytoicon = array(
	'invoice'      => 'bill',
	'invoice_line' => 'bill',
	'order'        => 'order',
	'order_line'   => 'order',
	'propal'       => 'propal',
	'propal_line'  => 'propal',
	'intervention' => 'intervention',
	'inter_line'   => 'intervention',
	'member'       => 'user',
	'member_type'  => 'group',
	'subscription' => 'payment',
	'payment'      => 'payment',
	'tax'          => 'bill',
	'tax_type'     => 'generic',
	'other'        => 'generic',
	'account'      => 'account',
	'product'      => 'product',
	'virtualproduct' => 'product',
	'subproduct'   => 'product',
	'product_supplier_ref'      => 'product',
	'stock'        => 'stock',
	'warehouse'    => 'stock',
	'batch'        => 'stock',
	'stockbatch'   => 'stock',
	'category'     => 'category',
	'shipment'     => 'sending',
	'shipment_line' => 'sending',
	'project'      => 'project',
	'task'  	   => 'tasks',
	'reception' => 'sending',
	'reception_line' => 'sending',
	'expensereport' => 'trip',
	'expensereport_line' => 'trip',
	'holiday'      => 'holiday',
	'contract_line' => 'contract',
	'translation'  => 'generic',
	'bomm'         => 'bom',
	'bomline'      => 'bom'
);

// Translation code, array duplicated in export.php, was not synchronized, TODO put it somewhere only once
$entitytolang = array(
	'user'         => 'User',
	'company'      => 'Company',
	'contact'      => 'Contact',
	'invoice'      => 'Bill',
	'invoice_line' => 'InvoiceLine',
	'order'        => 'Order',
	'order_line'   => 'OrderLine',
	'propal'       => 'Proposal',
	'propal_line'  => 'ProposalLine',
	'intervention' => 'Intervention',
	'inter_line'   => 'InterLine',
	'member'       => 'Member',
	'member_type'  => 'MemberType',
	'subscription' => 'Subscription',
	'tax'          => 'SocialContribution',
	'tax_type'     => 'DictionarySocialContributions',
	'account'      => 'BankTransactions',
	'payment'      => 'Payment',
	'product'      => 'Product',
	'virtualproduct'  => 'AssociatedProducts',
	'subproduct'      => 'SubProduct',
	'product_supplier_ref'      => 'SupplierPrices',
	'service'      => 'Service',
	'stock'        => 'Stock',
	'movement'	   => 'StockMovement',
	'batch'        => 'Batch',
	'stockbatch'   => 'StockDetailPerBatch',
	'warehouse'    => 'Warehouse',
	'category'     => 'Category',
	'other'        => 'Other',
	'trip'         => 'TripsAndExpenses',
	'shipment'     => 'Shipments',
	'shipment_line' => 'ShipmentLine',
	'project'      => 'Projects',
	'projecttask'  => 'Tasks',
	'task_time'    => 'TaskTimeSpent',
	'action'       => 'Event',
	'expensereport' => 'ExpenseReport',
	'expensereport_line' => 'ExpenseReportLine',
	'holiday'      => 'TitreRequestCP',
	'contract'     => 'Contract',
	'contract_line' => 'ContractLine',
	'translation'  => 'Translation',
	'bom'          => 'BOM',
	'bomline'      => 'BOMLine'
);

$datatoimport		= GETPOST('datatoimport');
$format				= GETPOST('format');
$filetoimport		= GETPOST('filetoimport');
$action				= GETPOST('action', 'alpha');
$confirm			= GETPOST('confirm', 'alpha');
$step				= (GETPOST('step') ? GETPOST('step') : 1);
$import_name = GETPOST('import_name');
$hexa = GETPOST('hexa');
$importmodelid = GETPOSTINT('importmodelid');
$excludefirstline = (GETPOST('excludefirstline') ? GETPOST('excludefirstline') : 2);
$endatlinenb = (GETPOST('endatlinenb') ? GETPOST('endatlinenb') : '');
$updatekeys			= (GETPOST('updatekeys', 'array') ? GETPOST('updatekeys', 'array') : array());
$separator			= (GETPOST('separator', 'nohtml') ? GETPOST('separator', 'nohtml', 3) : '');
$enclosure			= (GETPOST('enclosure', 'nohtml') ? GETPOST('enclosure', 'nohtml') : '"');	// We must use 'nohtml' and not 'alphanohtml' because we must accept "
$charset            = GETPOST('charset', 'aZ09');
$separator_used     = str_replace('\t', "\t", $separator);
$relativepath = '';

$objimport = new Import($db);
$objimport->load_arrays($user, ($step == 1 ? '' : $datatoimport));

if (empty($updatekeys) && !empty($objimport->array_import_preselected_updatekeys[0])) {
	$updatekeys = $objimport->array_import_preselected_updatekeys[0];
}

$objmodelimport = new ModeleImports();

$form = new Form($db);
$htmlother = new FormOther($db);
$formfile = new FormFile($db);

// Init $array_match_file_to_database from _SESSION
if (empty($array_match_file_to_database)) {
	$serialized_array_match_file_to_database = isset($_SESSION["dol_array_match_file_to_database_select"]) ? $_SESSION["dol_array_match_file_to_database_select"] : '';
	$array_match_file_to_database = array();
	$fieldsarray = explode(',', $serialized_array_match_file_to_database);
	foreach ($fieldsarray as $elem) {
		$tabelem = explode('=', $elem, 2);
		$key = $tabelem[0];
		$val = (isset($tabelem[1]) ? $tabelem[1] : '');
		if ($key && $val) {
			$array_match_file_to_database[$key] = $val;
		}
	}
}


/*
 * Actions
 */

if ($action == 'deleteprof' && $user->hasRight('import', 'run')) {
	if (GETPOSTINT("id")) {
		$objimport->fetch(GETPOSTINT("id"));
		$result = $objimport->delete($user);
	}
}

// Save import config to database
if ($action == 'add_import_model' && $user->hasRight('import', 'run')) {
	if ($import_name) {
		// Set save string
		$hexa = '';
		foreach ($array_match_file_to_database as $key => $val) {
			if ($hexa) {
				$hexa .= ',';
			}
			$hexa .= $key.'='.$val;
		}

		$objimport->model_name = $import_name;
		$objimport->datatoimport = $datatoimport;
		$objimport->hexa = $hexa;
		$objimport->fk_user = (GETPOST('visibility', 'aZ09') == 'all' ? 0 : $user->id);

		$result = $objimport->create($user);
		if ($result >= 0) {
			setEventMessages($langs->trans("ImportModelSaved", $objimport->model_name), null, 'mesgs');
			$import_name = '';
		} else {
			$langs->load("errors");
			if ($objimport->errno == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
				setEventMessages($langs->trans("ErrorImportDuplicateProfil"), null, 'errors');
			} else {
				setEventMessages($objimport->error, null, 'errors');
			}
		}
	} else {
		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("ImportModelName")), null, 'errors');
	}
}

if ($step == 3 && $datatoimport) {
	if (GETPOST('sendit') && getDolGlobalString('MAIN_UPLOAD_DOC')) {
		dol_mkdir($conf->import->dir_temp);
		$nowyearmonth = dol_print_date(dol_now(), '%Y%m%d%H%M%S');

		$fullpath = $conf->import->dir_temp."/".$nowyearmonth.'-'.dol_string_nohtmltag(dol_sanitizeFileName($_FILES['userfile']['name']));
		if (dol_move_uploaded_file($_FILES['userfile']['tmp_name'], $fullpath, 1) > 0) {
			dol_syslog("File ".$fullpath." was added for import");
		} else {
			$langs->load("errors");
			setEventMessages($langs->trans("ErrorFailedToSaveFile"), null, 'errors');
		}
	}

	// Delete file
	if ($action == 'confirm_deletefile' && $confirm == 'yes' && $user->hasRight('import', 'run')) {
		$langs->load("other");

		$param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
		if ($excludefirstline) {
			$param .= '&excludefirstline='.urlencode($excludefirstline);
		}
		if ($endatlinenb) {
			$param .= '&endatlinenb='.urlencode($endatlinenb);
		}

		$file = $conf->import->dir_temp.'/'.GETPOST('urlfile');
		$ret = dol_delete_file($file);
		if ($ret) {
			setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
		} else {
			setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
		}
		header('Location: '.$_SERVER["PHP_SELF"].'?step='.$step.$param);
		exit;
	}
}

if ($step == 4 && $action == 'select_model' && $user->hasRight('import', 'run')) {
	// Reinit match arrays
	$_SESSION["dol_array_match_file_to_database"] = '';
	$serialized_array_match_file_to_database = '';
	$array_match_file_to_database = array();

	// Load model from $importmodelid and set $array_match_file_to_database
	// and $_SESSION["dol_array_match_file_to_database"]
	$result = $objimport->fetch($importmodelid);
	if ($result > 0) {
		$serialized_array_match_file_to_database = $objimport->hexa;
		$fieldsarray = explode(',', $serialized_array_match_file_to_database);
		foreach ($fieldsarray as $elem) {
			$tabelem = explode('=', $elem);
			$key = $tabelem[0];
			$val = $tabelem[1];
			if ($key && $val) {
				$array_match_file_to_database[$key] = $val;
			}
		}
		$_SESSION["dol_array_match_file_to_database"] = $serialized_array_match_file_to_database;
		$_SESSION['dol_array_match_file_to_database_select'] = $_SESSION["dol_array_match_file_to_database"];
	}
}
if ($action == 'saveselectorder' && $user->hasRight('import', 'run')) {
	// Enregistrement de la position des champs
	$serialized_array_match_file_to_database = '';
	dol_syslog("selectorder=".GETPOST('selectorder'), LOG_DEBUG);
	$selectorder = explode(",", GETPOST('selectorder'));
	$fieldtarget = $fieldstarget = $objimport->array_import_fields[0];
	foreach ($selectorder as $key => $code) {
		$serialized_array_match_file_to_database .= $key.'='.$code;
		$serialized_array_match_file_to_database .= ',';
	}
	$serialized_array_match_file_to_database = substr($serialized_array_match_file_to_database, 0, -1);
	dol_syslog('dol_array_match_file_to_database_select='.$serialized_array_match_file_to_database);
	$_SESSION["dol_array_match_file_to_database_select"] = $serialized_array_match_file_to_database;
	echo "{}";
	exit(0);
}


/*
 * View
 */

$help_url = 'EN:Module_Imports_En|FR:Module_Imports|ES:M&oacute;dulo_Importaciones';

// STEP 1: Page to select dataset to import
if ($step == 1 || !$datatoimport) {
	// Clean saved file-database matching
	$serialized_array_match_file_to_database = '';
	$array_match_file_to_database = array();
	$_SESSION["dol_array_match_file_to_database"] = '';
	$_SESSION["dol_array_match_file_to_database_select"] = '';

	$param = '';
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if ($separator) {
		$param .= '&separator='.urlencode($separator);
	}
	if ($enclosure) {
		$param .= '&enclosure='.urlencode($enclosure);
	}

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 1);

	print dol_get_fiche_head($head, 'step1', 'Import', -1, 'upload');

	print '<div class="opacitymedium">'.$langs->trans("SelectImportDataSet").'</div>';


	// Define $nbmodulesnotautoenabled - TODO This code is at different places
	$nbmodulesnotautoenabled = count($conf->modules);
	$listofmodulesautoenabled = array('user', 'agenda', 'fckeditor', 'export', 'import');
	foreach ($listofmodulesautoenabled as $moduleautoenable) {
		if (in_array($moduleautoenable, $conf->modules)) {
			$nbmodulesnotautoenabled--;
		}
	}

	if ($user->admin && $nbmodulesnotautoenabled < getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) {	// If only minimal initial modules enabled
		print info_admin($langs->trans("WarningOnlyProfilesOfActivatedModules").' '.$langs->trans("YouCanEnableModulesFrom"));
	}

	print '<br>';

	// Show profile for import
	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
	print '<table class="noborder centpercent nomarginbottom">';
	print '<tr class="liste_titre">';
	print '<td>'.$langs->trans("Module").'</td>';
	print '<td>'.$langs->trans("ImportableDatas").'</td>';
	print '<td>&nbsp;</td>';
	print '</tr>';

	if (count($objimport->array_import_module)) {
		$sortedarrayofmodules = dol_sort_array($objimport->array_import_module, 'position_of_profile', 'asc', 0, 0, 1);
		foreach ($sortedarrayofmodules as $key => $value) {
			//var_dump($key.' '.$value['position_of_profile'].' '.$value['import_code'].' '.$objimport->array_import_module[$key]['module']->getName().' '.$objimport->array_import_code[$key]);
			$titleofmodule = $objimport->array_import_module[$key]['module']->getName();
			print '<tr class="oddeven"><td class="tdoverflowmax200" title="'.dolPrintHTML($titleofmodule).'">';
			// Special case for import common to module/services
			if (in_array($objimport->array_import_code[$key], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
				$titleofmodule = $langs->trans("ProductOrService");
			}
			print dolPrintHTML($titleofmodule);
			print '</td><td>';
			$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[$key]);
			$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
			$label = $objimport->array_import_label[$key];
			print '<div class="twolinesmax-normallineheight minwidth200onall">';
			print img_object($objimport->array_import_module[$key]['module']->getName(), $entityicon, 'class="pictofixedwidth"');
			print dolPrintHTML($label);
			print '</div>';
			print '</td><td style="text-align: right">';
			if ($objimport->array_import_perms[$key]) {
				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>';
			} else {
				print $langs->trans("NotEnoughPermissions");
			}
			print '</td></tr>';
		}
	} else {
		print '<tr><td class="oddeven" colspan="3">'.$langs->trans("NoImportableData").'</td></tr>';
	}
	print '</table>';
	print '</div>';

	print dol_get_fiche_end();
}


// STEP 2: Page to select input format file
if ($step == 2 && $datatoimport) {
	$param = '&datatoimport='.urlencode($datatoimport);
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if ($separator) {
		$param .= '&separator='.urlencode($separator);
	}
	if ($enclosure) {
		$param .= '&enclosure='.urlencode($enclosure);
	}

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 2);

	print dol_get_fiche_head($head, 'step2', 'Import', -2, 'upload');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table class="border tableforfield centpercent">';

	// Module
	print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
	print '<td>';
	$titleofmodule = $objimport->array_import_module[0]['module']->getName();
	// Special case for import common to module/services
	if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
		$titleofmodule = $langs->trans("ProductOrService");
	}
	print $titleofmodule;
	print '</td></tr>';

	// Dataset to import
	print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
	print '<td>';
	$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
	$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
	print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
	print $objimport->array_import_label[0];
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print dol_get_fiche_end();

	print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" METHOD="POST">';
	print '<input type="hidden" name="token" value="'.newToken().'">';

	print '<br>';

	print '<span class="opacitymedium">';
	$s = $langs->trans("ChooseFormatOfFileToImport", '{s1}');
	$s = str_replace('{s1}', img_picto('', 'next'), $s);
	print $s;
	print '</span><br><br>';

	print '<br>';

	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
	print '<table class="noborder centpercent" cellpadding="4">';

	$filetoimport = '';

	// Add format information and link to download example
	print '<tr class="liste_titre"><td colspan="5">';
	print $langs->trans("FileMustHaveOneOfFollowingFormat");
	print '</td></tr>';
	$list = $objmodelimport->listOfAvailableImportFormat($db);
	foreach ($list as $key) {
		print '<tr class="oddeven">';
		print '<td width="16">'.img_picto_common($key, $objmodelimport->getPictoForKey($key)).'</td>';
		$htmltext = $objmodelimport->getDriverDescForKey($key);
		print '<td>'.$form->textwithpicto($objmodelimport->getDriverLabelForKey($key), $htmltext).'</td>';
		print '<td style="text-align:center">';
		if (empty($objmodelimport->drivererror[$key])) {
			$filename = $langs->transnoentitiesnoconv("ExampleOfImportFile").'_'.$datatoimport.'.'.$key;
			print '<a href="'.DOL_URL_ROOT.'/imports/emptyexample.php?format='.$key.$param.'&output=file&file='.urlencode($filename).'" target="_blank" rel="noopener noreferrer">';
			print img_picto('', 'download', 'class="paddingright opacitymedium"');
			print $langs->trans("DownloadEmptyExampleShort");
			print '</a>';
			print $form->textwithpicto('', $langs->trans("DownloadEmptyExample").'.<br>'.$langs->trans("StarAreMandatory"));
		} else {
			print dolPrintHTML($objmodelimport->drivererror[$key]);
		}
		print '</td>';
		// Action button
		print '<td style="text-align:right">';
		if (empty($objmodelimport->drivererror[$key])) {
			print '<a href="'.DOL_URL_ROOT.'/imports/import.php?step=3&format='.$key.$param.'">'.img_picto($langs->trans("SelectFormat"), 'next', 'class="fa-15"').'</a>';
		}
		print '</td>';
		print '</tr>';
	}

	print '</table>';
	print '</div>';

	print '</form>';
}


// STEP 3: Page to select file
if ($step == 3 && $datatoimport) {
	$param = '&datatoimport='.urlencode($datatoimport).'&format='.urlencode($format);
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if ($separator) {
		$param .= '&separator='.urlencode($separator);
	}
	if ($enclosure) {
		$param .= '&enclosure='.urlencode($enclosure);
	}

	$list = $objmodelimport->listOfAvailableImportFormat($db);

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 3);

	print dol_get_fiche_head($head, 'step3', 'Import', -2, 'upload');

	/*
	 * Confirm delete file
	 */
	if ($action == 'delete') {
		print $form->formconfirm($_SERVER["PHP_SELF"].'?urlfile='.urlencode(GETPOST('urlfile')).'&step=3'.$param, $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', 0, 1);
	}

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table class="border tableforfield centpercent">';

	// Module
	print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
	print '<td>';
	$titleofmodule = $objimport->array_import_module[0]['module']->getName();
	// Special case for import common to module/services
	if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
		$titleofmodule = $langs->trans("ProductOrService");
	}
	print $titleofmodule;
	print '</td></tr>';

	// Lot de donnees a importer
	print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
	print '<td>';
	$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
	$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
	print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
	print $objimport->array_import_label[0];
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';
	print '<table width="100%" class="border tableforfield">';

	// Source file format
	print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
	print '<td class="nowraponall">';
	$text = $objmodelimport->getDriverDescForKey($format);
	// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
	print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
	print '</td><td style="text-align:right" class="nowrap">';
	$filename = $langs->transnoentitiesnoconv("ExampleOfImportFile").'_'.$datatoimport.'.'.$format;
	print '<a href="'.DOL_URL_ROOT.'/imports/emptyexample.php?format='.$format.$param.'&output=file&file='.urlencode($filename).'" target="_blank" rel="noopener noreferrer">';
	print img_picto('', 'download', 'class="paddingright opacitymedium"');
	print $langs->trans("DownloadEmptyExampleShort");
	print '</a>';
	print $form->textwithpicto('', $langs->trans("DownloadEmptyExample").'.<br>'.$langs->trans("StarAreMandatory"));
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print dol_get_fiche_end();


	if ($format == 'xlsx' && !class_exists('XMLWriter')) {
		$langs->load("install");
		print info_admin($langs->trans("ErrorPHPDoesNotSupport", 'php-xml'), 0, 0, '1', 'error');
	}


	print '<br><br>';

	print '<form name="userfile" action="'.$_SERVER["PHP_SELF"].'" enctype="multipart/form-data" method="POST">';
	print '<input type="hidden" name="token" value="'.newToken().'">';
	print '<input type="hidden" value="'.$step.'" name="step">';
	print '<input type="hidden" value="'.dol_escape_htmltag($format).'" name="format">';
	print '<input type="hidden" value="'.$excludefirstline.'" name="excludefirstline">';
	print '<input type="hidden" value="'.$endatlinenb.'" name="endatlinenb">';
	print '<input type="hidden" value="'.dol_escape_htmltag($separator).'" name="separator">';
	print '<input type="hidden" value="'.dol_escape_htmltag($enclosure).'" name="enclosure">';
	print '<input type="hidden" value="'.dol_escape_htmltag($datatoimport).'" name="datatoimport">';

	print '<span class="opacitymedium">';
	$s = $langs->trans("ChooseFileToImport", '{s1}');
	$s = str_replace('{s1}', img_picto('', 'next'), $s);
	print $s;
	print '</span><br><br>';

	$filetoimport = '';

	// Input file name box
	print '<div class="marginbottomonly">';
	$maxfilesizearray = getMaxFileSizeArray();
	$maxmin = $maxfilesizearray['maxmin'];
	if ($maxmin > 0) {
		print '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">';	// MAX_FILE_SIZE must precede the field type=file
	}
	print '<input type="file" name="userfile" size="20" maxlength="80"> &nbsp; &nbsp; ';
	$out = (!getDolGlobalString('MAIN_UPLOAD_DOC') ? ' disabled' : '');
	print '<input type="submit" class="button small" value="'.$langs->trans("AddFile").'"'.$out.' name="sendit">';
	$out = '';
	if (getDolGlobalString('MAIN_UPLOAD_DOC')) {
		$max = getDolGlobalString('MAIN_UPLOAD_DOC'); // In Kb
		$maxphp = @ini_get('upload_max_filesize'); // In unknown
		if (preg_match('/k$/i', $maxphp)) {
			$maxphp = (int) substr($maxphp, 0, -1);
		}
		if (preg_match('/m$/i', $maxphp)) {
			$maxphp = (int) substr($maxphp, 0, -1) * 1024;
		}
		if (preg_match('/g$/i', $maxphp)) {
			$maxphp = (int) substr($maxphp, 0, -1) * 1024 * 1024;
		}
		if (preg_match('/t$/i', $maxphp)) {
			$maxphp = (int) substr($maxphp, 0, -1) * 1024 * 1024 * 1024;
		}
		$maxphp2 = @ini_get('post_max_size'); // In unknown
		if (preg_match('/k$/i', $maxphp2)) {
			$maxphp2 = (int) substr($maxphp2, 0, -1);
		}
		if (preg_match('/m$/i', $maxphp2)) {
			$maxphp2 = (int) substr($maxphp2, 0, -1) * 1024;
		}
		if (preg_match('/g$/i', $maxphp2)) {
			$maxphp2 = (int) substr($maxphp2, 0, -1) * 1024 * 1024;
		}
		if (preg_match('/t$/i', $maxphp2)) {
			$maxphp2 = (int) substr($maxphp2, 0, -1) * 1024 * 1024 * 1024;
		}
		// Now $max and $maxphp and $maxphp2 are in Kb
		$maxmin = $max;
		$maxphptoshow = $maxphptoshowparam = '';
		if ($maxphp > 0) {
			$maxmin = min($max, $maxphp);
			$maxphptoshow = $maxphp;
			$maxphptoshowparam = 'upload_max_filesize';
		}
		if ($maxphp2 > 0) {
			$maxmin = min($max, $maxphp2);
			if ($maxphp2 < $maxphp) {
				$maxphptoshow = $maxphp2;
				$maxphptoshowparam = 'post_max_size';
			}
		}

		$langs->load('other');
		$out .= ' ';
		$out .= info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow), 1);
	} else {
		$out .= ' ('.$langs->trans("UploadDisabled").')';
	}
	print $out;
	print '</div>';

	// Search available imports
	$filearray = dol_dir_list($conf->import->dir_temp, 'files', 0, '', '', 'name', SORT_DESC);
	if (count($filearray) > 0) {
		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
		print '<table class="noborder centpercent" width="100%" cellpadding="4">';

		$dir = $conf->import->dir_temp;

		// Search available files to import
		$i = 0;
		foreach ($filearray as $key => $val) {
			$file = $val['name'];

			// readdir return value in ISO and we want UTF8 in memory
			if (!utf8_check($file)) {
				$file = mb_convert_encoding($file, 'UTF-8', 'ISO-8859-1');
			}

			if (preg_match('/^\./', $file)) {
				continue;
			}

			$modulepart = 'import';
			$urlsource = $_SERVER["PHP_SELF"].'?step='.$step.$param.'&filetoimport='.urlencode($filetoimport);
			$relativepath = $file;

			print '<tr class="oddeven">';
			print '<td>';
			print img_mime($file, '', 'pictofixedwidth');
			print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=3'.$param.'" target="_blank" rel="noopener noreferrer">';
			print $file;
			print '</a>';
			print '</td>';
			// Affiche taille fichier
			print '<td style="text-align:right">'.dol_print_size(dol_filesize($dir.'/'.$file)).'</td>';
			// Affiche date fichier
			print '<td style="text-align:right">'.dol_print_date(dol_filemtime($dir.'/'.$file), 'dayhour').'</td>';
			// Del button
			print '<td style="text-align:right"><a href="'.$_SERVER['PHP_SELF'].'?action=delete&token='.newToken().'&step=3'.$param.'&urlfile='.urlencode($relativepath);
			print '">'.img_delete().'</a></td>';
			// Action button
			print '<td style="text-align:right">';
			print '<a href="'.$_SERVER['PHP_SELF'].'?step=4'.$param.'&filetoimport='.urlencode($relativepath).'">'.img_picto($langs->trans("NewImport"), 'next', 'class="fa-15"').'</a>';
			print '</td>';
			print '</tr>';
		}

		print '</table>';
		print '</div>';
	}

	print '</form>';
}


// STEP 4: Page to make matching between source file and database fields
if ($step == 4 && $datatoimport) {
	//var_dump($_SESSION["dol_array_match_file_to_database_select"]);
	$serialized_array_match_file_to_database = isset($_SESSION["dol_array_match_file_to_database_select"]) ? $_SESSION["dol_array_match_file_to_database_select"] : '';
	$fieldsarray = explode(',', $serialized_array_match_file_to_database);
	$array_match_file_to_database = array();		// Same than $fieldsarray but with mapped value only  (col1 => 's.fielda', col2 => 's.fieldb'...)
	foreach ($fieldsarray as $elem) {
		$tabelem = explode('=', $elem, 2);
		$key = $tabelem[0];
		$val = (isset($tabelem[1]) ? $tabelem[1] : '');
		if ($key && $val) {
			$array_match_file_to_database[$key] = $val;
		}
	}

	//var_dump($serialized_array_match_file_to_database);
	//var_dump($fieldsarray);
	//var_dump($array_match_file_to_database);

	$model = $format;
	$list = $objmodelimport->listOfAvailableImportFormat($db);

	if (empty($separator)) {
		$separator = (!getDolGlobalString('IMPORT_CSV_SEPARATOR_TO_USE') ? ',' : $conf->global->IMPORT_CSV_SEPARATOR_TO_USE);
	}

	// The separator has been defined, if it is a unique char, we check it is valid by reading the source file
	if ($model == 'csv' && strlen($separator) == 1 && !GETPOSTISSET('separator')) {
		'@phan-var-force ImportCsv $obj';
		// Count the char in first line of file.
		$fh = fopen($conf->import->dir_temp.'/'.$filetoimport, 'r');
		if ($fh) {
			$sline = fgets($fh, 1000000);
			fclose($fh);
			$nboccurence = substr_count($sline, $separator);
			$nboccurencea = substr_count($sline, ',');
			$nboccurenceb = substr_count($sline, ';');
			//var_dump($nboccurence." ".$nboccurencea." ".$nboccurenceb);exit;
			if ($nboccurence == 0) {
				if ($nboccurencea > 2) {
					$separator = ',';
				} elseif ($nboccurenceb > 2) {
					$separator = ';';
				}
			}
		}
	}

	// The value to use
	$separator_used = str_replace('\t', "\t", $separator);

	// Create class to use for import
	$dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
	$file = "import_".$model.".modules.php";
	$classname = "Import".ucfirst($model);
	require_once $dir.$file;
	$obj = new $classname($db, $datatoimport);
	'@phan-var-force ModeleImports $obj';

	if (!empty($obj->error)) {
		$langs->load("errors");
		$param = '&datatoimport='.$datatoimport.'&format='.$format;
		setEventMessages($obj->error, null, 'errors');
		header("Location: ".$_SERVER["PHP_SELF"].'?step=3'.$param.'&filetoimport='.urlencode($relativepath));
		exit;
	}

	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		$obj->separator = $separator_used;
		$obj->enclosure = $enclosure;
		$obj->charset = '';
	}
	if ($model == 'xlsx') {
		'@phan-var-force ImportXlsx $obj';
		if (!preg_match('/\.xlsx$/i', $filetoimport)) {
			$langs->load("errors");
			$param = '&datatoimport='.$datatoimport.'&format='.$format;
			setEventMessages($langs->trans("ErrorFileMustHaveFormat", $model), null, 'errors');
			header("Location: ".$_SERVER["PHP_SELF"].'?step=3'.$param.'&filetoimport='.urlencode($relativepath));
			exit;
		}
	}

	if (GETPOST('update')) {
		$array_match_file_to_database = array();
	}

	// Load the source fields from input file into variable $arrayrecord
	$fieldssource = array();
	/** @var array<string,string> $fieldssource */
	$result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport);
	if ($result >= 0) {
		// Read first line
		$arrayrecord = $obj->import_read_record();

		// Create array $fieldssource starting with 1 with values found of first line.
		$i = 1;
		foreach ($arrayrecord as $key => $val) {
			if ($val["type"] != -1) {
				$fieldssource[$i]['example1'] = dol_trunc($val['val'], 128);
			} else {
				$fieldssource[$i]['example1'] = $langs->trans('Empty');
			}
			$fieldssource[$i]['imported'] = false;
			$i++;
		}
		$obj->import_close_file();
	}

	// Load targets fields in database
	$fieldstarget = $objimport->array_import_fields[0];
	$minpos = min(count($fieldssource), count($fieldstarget));
	//var_dump($array_match_file_to_database);


	$initialloadofstep4 = false;
	if (empty($_SESSION['dol_array_match_file_to_database_select'])) {
		$initialloadofstep4 = true;
	}

	// Is it a first time in page (if yes, we must initialize array_match_file_to_database)
	if (count($array_match_file_to_database) == 0) {
		// This is first input in screen, we need to define
		// $array_match_file_to_database
		// $serialized_array_match_file_to_database
		// $_SESSION["dol_array_match_file_to_database"]
		$pos = 1;
		$num = count($fieldssource);
		while ($pos <= $num) {
			if ($num >= 1 && $pos <= $num) {
				$posbis = 1;
				foreach ($fieldstarget as $key => $val) {
					if ($posbis < $pos) {
						$posbis++;
						continue;
					}
					// We found the key of targets that is at position pos
					$array_match_file_to_database[$pos] = $key;
					break;
				}
			}
			$pos++;
		}
	}
	$array_match_database_to_file = array_flip($array_match_file_to_database);
	//var_dump($array_match_database_to_file);
	//var_dump($_SESSION["dol_array_match_file_to_database_select"]);

	$fieldstarget_tmp = array();
	$arraykeysfieldtarget = array_keys($fieldstarget);
	$position = 0;
	foreach ($fieldstarget as $key => $label) {
		$isrequired = preg_match('/\*$/', $label);
		if (!empty($isrequired)) {
			$newlabel = substr($label, 0, -1);
			$fieldstarget_tmp[$key] = array("label" => $newlabel, "required" => true);
		} else {
			$fieldstarget_tmp[$key] = array("label" => $label, "required" => false);
		}
		if (!empty($array_match_database_to_file[$key])) {
			$fieldstarget_tmp[$key]["imported"] = true;
			$fieldstarget_tmp[$key]["position"] = (int) $array_match_database_to_file[$key] - 1;
			$keytoswap = $key;
			while (!empty($array_match_database_to_file[$keytoswap])) {
				if ($position + 1 > $array_match_database_to_file[$keytoswap]) {
					$keytoswapwith = $array_match_database_to_file[$keytoswap] - 1;
					$tmp = [$keytoswap => $fieldstarget_tmp[$keytoswap]];
					unset($fieldstarget_tmp[$keytoswap]);
					$fieldstarget_tmp = arrayInsert($fieldstarget_tmp, $keytoswapwith, $tmp);
					$keytoswapwith = $arraykeysfieldtarget[$array_match_database_to_file[$keytoswap] - 1];
					$tmp = $fieldstarget_tmp[$keytoswapwith];
					unset($fieldstarget_tmp[$keytoswapwith]);
					$fieldstarget_tmp[$keytoswapwith] = $tmp;
					$keytoswap = $keytoswapwith;
				} else {
					break;
				}
			}
		} else {
			$fieldstarget_tmp[$key]["imported"] = false;
		}
		$position++;
	}
	$fieldstarget = $fieldstarget_tmp;

	//print $serialized_array_match_file_to_database;
	//print $_SESSION["dol_array_match_file_to_database"];
	//print $_SESSION["dol_array_match_file_to_database_select"];
	//var_dump($array_match_file_to_database);exit;

	// Now $array_match_file_to_database contains  fieldnb(1,2,3...)=>fielddatabase(key in $array_match_file_to_database)

	$param = '&format='.$format.'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport);
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if ($separator) {
		$param .= '&separator='.urlencode($separator);
	}
	if ($enclosure) {
		$param .= '&enclosure='.urlencode($enclosure);
	}

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 4);

	print dol_get_fiche_head($head, 'step4', 'Import', -2, 'upload');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table class="centpercent border tableforfield">';

	// Module
	print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
	print '<td>';
	$titleofmodule = $objimport->array_import_module[0]['module']->getName();
	// Special case for import common to module/services
	if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
		$titleofmodule = $langs->trans("ProductOrService");
	}
	print $titleofmodule;
	print '</td></tr>';

	// Lot de donnees a importer
	print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
	print '<td>';
	$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
	$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
	print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
	print $objimport->array_import_label[0];
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';
	print '<table width="100%" class="border tableforfield">';

	// Source file format
	print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
	print '<td class="nowraponall">';
	$text = $objmodelimport->getDriverDescForKey($format);
	// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
	print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
	print '</td></tr>';

	// Separator and enclosure
	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
		print '<td>';
		print '<form method="POST">';
		print '<input type="hidden" name="token" value="'.newToken().'">';
		print '<input type="hidden" value="'.$step.'" name="step">';
		print '<input type="hidden" value="'.$format.'" name="format">';
		print '<input type="hidden" value="'.$excludefirstline.'" name="excludefirstline">';
		print '<input type="hidden" value="'.$endatlinenb.'" name="endatlinenb">';
		print '<input type="hidden" value="'.$datatoimport.'" name="datatoimport">';
		print '<input type="hidden" value="'.$filetoimport.'" name="filetoimport">';
		print $langs->trans("Separator").' : ';
		print '<input type="text" class="width25 center" name="separator" value="'.dol_escape_htmltag($separator).'"/>';
		print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : ';
		print '<input type="text" class="width25 center" name="enclosure" value="'.dol_escape_htmltag($enclosure).'"/> ';
		print '<input name="update" type="submit" value="'.$langs->trans('Update').'" class="button smallpaddingimp" />';
		print '</form>';
		print '</td></tr>';
	}

	// File to import
	print '<tr><td>'.$langs->trans("FileToImport").'</td>';
	print '<td>';
	$modulepart = 'import';
	$relativepath = GETPOST('filetoimport');
	print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
	print img_mime($file, '', 'pictofixedwidth');
	print $filetoimport;
	print img_picto($langs->trans("Download"), 'download', 'class="paddingleft opacitymedium"');
	print '</a>';
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print dol_get_fiche_end();

	print '<br>'."\n";


	// List of source fields
	print '<!-- List of source fields -->'."\n";
	print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
	print '<input type="hidden" name="token" value="'.newToken().'">';
	print '<input type="hidden" name="action" value="select_model">';
	print '<input type="hidden" name="step" value="4">';
	print '<input type="hidden" name="format" value="'.$format.'">';
	print '<input type="hidden" name="datatoimport" value="'.$datatoimport.'">';
	print '<input type="hidden" name="filetoimport" value="'.$filetoimport.'">';
	print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
	print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
	print '<input type="hidden" name="separator" value="'.dol_escape_htmltag($separator).'">';
	print '<input type="hidden" name="enclosure" value="'.dol_escape_htmltag($enclosure).'">';

	// Import profile to use/load
	print '<div class="marginbottomonly">';
	print '<span class="opacitymedium">';
	$s = $langs->trans("SelectImportFieldsSource", '{s1}');
	$s = str_replace('{s1}', img_picto('', 'grip_title', '', 0, 0, 0, '', '', 0), $s);
	print $s;
	print '</span> ';
	$htmlother->select_import_model((string) $importmodelid, 'importmodelid', $datatoimport, 1, $user->id);
	print '<input type="submit" class="button smallpaddingimp reposition" value="'.$langs->trans("Select").'">';
	print '</div>';
	print '</form>';

	// Title of array with fields
	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
	print '<table class="noborder centpercent">';
	print '<tr class="liste_titre">';
	print '<td>'.$langs->trans("FieldsInSourceFile").'</td>';
	print '<td>'.$langs->trans("FieldsInTargetDatabase").'</td>';
	print '</tr>';

	//var_dump($array_match_file_to_database);

	print '<tr valign="top"><td width="50%" class="nopaddingleftimp">';

	$fieldsplaced = array();
	$valforsourcefieldnb = array();
	$listofkeys = array();
	foreach ($array_match_file_to_database as $key => $val) {
		$listofkeys[$key] = 1;
	}

	print "\n<!-- Box left container -->\n";
	print '<div id="left" class="connectedSortable">'."\n";

	// List of source fields

	$lefti = 1;
	foreach ($fieldssource as $key => $val) {
		show_elem($fieldssource, $key, (string) $key); // key is field number in source file @phan-suppress-current-line PhanPluginSuspiciousParamPosition
		$listofkeys[$key] = 1;
		$fieldsplaced[$key] = 1;
		$valforsourcefieldnb[$lefti] = $key;
		$lefti++;

		/*if ($lefti > count($fieldstarget)) {
			break; // Other fields are in the not imported area
		}*/
	}
	//var_dump($valforsourcefieldnb);

	print "</div>\n";
	print "<!-- End box left container -->\n";


	print '</td><td width="50%" class="nopaddingrightimp">';

	// Set the list of all possible target fields in Dolibarr.

	$optionsall = array();
	foreach ($fieldstarget as $code => $line) {
		$tmparray = explode('|', $line["label"]);	// If label of field is several translation keys separated with |
		$labeltoshow = '';
		foreach ($tmparray as $tmpkey => $tmpval) {
			$labeltoshow .= ($labeltoshow ? ' '.$langs->trans('or').' ' : '').$langs->transnoentities($tmpval);
		}
		// TODO Get type from a new array into module descriptor.
		// $picto = 'email';
		$picto = '';
		$optionsall[$code] = array(
			'labelkey' => $line['label'],
			'labelkeyarray' => $tmparray,
			'label' => $labeltoshow,
			'required' => (empty($line["required"]) ? 0 : 1),
			'position' => (!empty($line['position']) ? $line['position'] : 0),
			'picto' => $picto,
		);
	}
	// $optionsall is an array of all possible target fields. key=>array('label'=>..., 'xxx')

	$height = '32px'; //needs px for css height attribute below
	$i = 0;
	$mandatoryfieldshavesource = true;

	//var_dump($fieldstarget);
	//var_dump($optionsall);
	//exit;

	//var_dump($_SESSION['dol_array_match_file_to_database']);
	//var_dump($_SESSION['dol_array_match_file_to_database_select']);
	//exit;
	//var_dump($optionsall);
	//var_dump($fieldssource);
	//var_dump($fieldstarget);

	$modetoautofillmapping = 'session';		// Use setup in session
	if ($initialloadofstep4) {
		$modetoautofillmapping = 'guess';
	}
	//var_dump($modetoautofillmapping);

	print '<table class="nobordernopadding centpercent tableimport">';
	foreach ($fieldssource as $code => $line) {	// $fieldssource is an array code=column num,  line=content on first line for column in source file.
		/*if ($i == $minpos) {
			break;
		}*/
		//var_dump($line);
		print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
		// Note: $code is int, but index should be fieldname? -> @phan-suppress-next-line PhanTypeMismatchDimFetch
		$entity = (!empty($objimport->array_import_entities[0][$code]) ? $objimport->array_import_entities[0][$code] : $objimport->array_import_icon[0]);

		$entityicon = !empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity; // $entityicon must string name of picto of the field like 'project', 'company', 'contact', 'modulename', ...
		$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', 'MyModule', ...

		print '<td class="nowraponall hideonsmartphone" style="font-weight: normal">=> </td>';
		print '<td class="nowraponall" style="font-weight: normal">';

		$selectforline = '';
		$selectforline .= '<select id="selectorderimport_'.($i + 1).'" class="targetselectchange minwidth300" name="select_'.($i + 1).'">';
		$selectforline .= '<option value="-1">&nbsp;</option>';

		$j = 0;
		$codeselectedarray = array();
		foreach ($optionsall as $tmpcode => $tmpval) {	// Loop on each entry to add into each combo list.
			$label = '';
			if (!empty($tmpval['picto'])) {
				$label .= img_picto('', $tmpval['picto'], 'class="pictofixedwidth"');
			}
			$label .= $tmpval['required'] ? '<strong>' : '';
			$label .= $tmpval['label'];
			$label .= $tmpval['required'] ? '*</strong>' : '';

			$tablealias = preg_replace('/(\..*)$/i', '', $tmpcode);
			$tablename = !empty($objimport->array_import_tables[0][$tablealias]) ? $objimport->array_import_tables[0][$tablealias] : "";

			$htmltext = '';

			$filecolumn = ($i + 1);
			// Source field info
			if (empty($objimport->array_import_convertvalue[0][$tmpcode])) {	// If source file does not need conversion
				$filecolumntoshow = num2Alpha($i);
			} else {
				if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromref') {
					$htmltext .= $langs->trans("DataComeFromIdFoundFromRef", $langs->transnoentitiesnoconv($entitylang)).'<br>';
				}
				if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromcodeid') {
					$htmltext .= $langs->trans("DataComeFromIdFoundFromCodeId", $langs->transnoentitiesnoconv($objimport->array_import_convertvalue[0][$tmpcode]['dict'])).'<br>';
				}
			}
			// Source required
			$example = !empty($objimport->array_import_examplevalues[0][$tmpcode]) ? $objimport->array_import_examplevalues[0][$tmpcode] : "";
			// Example
			if (empty($objimport->array_import_convertvalue[0][$tmpcode])) {	// If source file does not need conversion
				if ($example) {
					$htmltext .= $langs->trans("SourceExample").': <b>'.str_replace('"', '', $example).'</b><br>';
				}
			} else {
				if ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromref') {
					$htmltext .= $langs->trans("SourceExample").': <b>'.$langs->transnoentitiesnoconv("ExampleAnyRefFoundIntoElement", $entitylang).($example ? ' ('.$langs->transnoentitiesnoconv("Example").': '.str_replace('"', '', $example).')' : '').'</b><br>';
				} elseif ($objimport->array_import_convertvalue[0][$tmpcode]['rule'] == 'fetchidfromcodeid') {
					$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>';
				} elseif ($example) {
					$htmltext .= $langs->trans("SourceExample").': <b>'.str_replace('"', '', $example).'</b><br>';
				}
			}
			// Format control rule
			if (!empty($objimport->array_import_regex[0][$tmpcode])) {
				$htmltext .= $langs->trans("FormatControlRule").': <b>'.str_replace('"', '', $objimport->array_import_regex[0][$tmpcode]).'</b><br>';
			}

			//var_dump($htmltext);
			$htmltext .= $langs->trans("InformationOnTargetTables").': &nbsp; <b>'.$tablename."->".preg_replace('/^.*\./', '', $tmpcode)."</b>";

			$labelhtml = $label.' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 1);


			$selectforline .= '<option value="'.$tmpcode.'"';
			if ($modetoautofillmapping == 'orderoftargets') {
				// 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.
				if ($j == $i) {
					$selectforline .= ' selected';
				}
			} elseif ($modetoautofillmapping == 'guess') {
				// The mode where we try to guess which value to preselect from the name in first column of source file.
				// $line['example1'] is the label of the column found on first line
				$regs = array();
				if (preg_match('/^(.+)\((.+\..+)\)$/', $line['example1'], $regs)) {	// If text is "Label (x.abc)"
					$tmpstring1 = $regs[1];
					$tmpstring2 = $regs[2];
				} else {
					$tmpstring1 = $line['example1'];
					$tmpstring2 = '';
				}
				$tmpstring1 = strtolower(dol_string_unaccent(str_replace('*', '', trim($tmpstring1))));
				$tmpstring2 = strtolower(dol_string_unaccent(str_replace('*', '', trim($tmpstring2))));

				// $tmpstring1 and $tmpstring2 are string from the input file title of column "Label (fieldname)".
				// $tmpval is array of target fields read from the module import profile.
				foreach ($tmpval['labelkeyarray'] as $tmpval2) {
					$labeltarget = $langs->transnoentities($tmpval2);
					//var_dump($tmpstring1.' - '.$tmpstring2.' - '.$tmpval['labelkey'].' - '.$tmpval['label'].' - '.$tmpval2.' - '.$labeltarget);
					if ($tmpstring1 && ($tmpstring1 == $tmpcode || $tmpstring1 == strtolower($labeltarget)
						|| $tmpstring1 == strtolower(dol_string_unaccent($labeltarget)) || $tmpstring1 == strtolower($tmpval2))) {
						if (empty($codeselectedarray[$code])) {
							$selectforline .= ' selected';
							$codeselectedarray[$code] = 1;
							break;
						}
					} elseif ($tmpstring2 && ($tmpstring2 == $tmpcode || $tmpstring2 == strtolower($labeltarget)
						|| $tmpstring2 == strtolower(dol_string_unaccent($labeltarget)) || $tmpstring2 == strtolower($tmpval2))) {
						if (empty($codeselectedarray[$code])) {
							$selectforline .= ' selected';
							$codeselectedarray[$code] = 1;
							break;
						}
					}
				}
			} elseif ($modetoautofillmapping == 'session' && !empty($_SESSION['dol_array_match_file_to_database_select'])) {
				$tmpselectioninsession = dolExplodeIntoArray($_SESSION['dol_array_match_file_to_database_select'], ',', '=');
				//var_dump($code);
				if (!empty($tmpselectioninsession[(string) ($i + 1)]) && $tmpselectioninsession[(string) ($i + 1)] == $tmpcode) {
					$selectforline .= ' selected';
				}
				$selectforline .= ' data-debug="'.$tmpcode.'-'.$code.'-'.$j.'-'.(!empty($tmpselectioninsession[(string) ($i + 1)]) ? $tmpselectioninsession[(string) ($i + 1)] : "").'"';
			}
			$selectforline .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
			$selectforline .= '>';
			$selectforline .= $label;
			$selectforline .= '</options>';
			$j++;
		}
		$selectforline .= '</select>';
		$selectforline .= ajax_combobox('selectorderimport_'.($i + 1));

		print $selectforline;

		print '</td>';

		// Tooltip at end of line
		print '<td class="nowraponall" style="font-weight:normal; text-align:right">';

		// Source field info
		$htmltext = '<b><u>'.$langs->trans("FieldSource").'</u></b><br>';
		$filecolumntoshow = num2Alpha($i);
		$htmltext .= $langs->trans("DataComeFromFileFieldNb", $filecolumntoshow).'<br>';

		print $form->textwithpicto('', $htmltext);

		print '</td>';
		print '</tr>';
		$i++;
	}
	print '</table>';

	print '</td></tr>';

	// Lines for remark
	print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Note").'</td></tr>';
	print '<tr><td colspan="2"><div id="div-mandatory-target-fields-not-mapped"></div></td></tr>';

	print '</table>';
	print '</div>';


	if (!empty($conf->use_javascript_ajax)) {
		print '<script type="text/javascript">'."\n";
		print 'var previousselectedvalueimport = "0";'."\n";
		print 'var previousselectedlabelimport = "0";'."\n";
		print 'var arrayofselectedvalues = [];'."\n";
		print 'var arrayoftargetfields = [];'."\n";
		print 'var arrayoftargetmandatoryfields = [];'."\n";

		// Loop on $fieldstarget (seems sorted by 'position') to store php array into javascript array
		$tmpi = 0;
		foreach ($fieldstarget as $key => $val) {
			print "arrayoftargetfields[".$tmpi."] = '".dol_escape_js($langs->trans($val['label']))."'; ";
			if ($val['required']) {
				print "arrayoftargetmandatoryfields[".$tmpi."] = '".dol_escape_js($key)."'; ";
			}
			$tmpi++;
		}
		print "\n";

		print '$(document).ready(function () {'."\n";

		print 'setOptionsToDisabled();'."\n";
		print 'saveSelection();'."\n";

		print '$(".targetselectchange").focus(function(){'."\n";
		print '		previousselectedvalueimport = $(this).val();'."\n";
		print '		previousselectedlabelimport = $(this).children("option:selected").text();'."\n";
		print '		console.log("previousselectedvalueimport="+previousselectedvalueimport)'."\n";
		print '})'."\n";

		// Function to set the disabled flag
		// - We set all option to "enabled"
		// - Then we scan all combo to get the value currently selected and save them into the array arrayofselectedvalues
		// - Then we set to disabled all fields that are selected
		print 'function setOptionsToDisabled() {'."\n";
		print '		console.log("Remove the disabled flag everywhere");'."\n";
		print '		$("select.targetselectchange").not($( this )).find(\'option\').prop("disabled", false);'."\n";	// Enable all options
		print '		arrayofselectedvalues = [];'."\n";

		print '		$("select.targetselectchange").each(function(){'."\n";
		print '			id = $(this).attr(\'id\')'."\n";
		print '			value = $(this).val()'."\n";
		print '         console.log("a selected value has been found for component "+id+" = "+value);'."\n";
		print '			arrayofselectedvalues.push(value);'."\n";
		print '		});'."\n";

		print '		console.log("List of all selected values arrayofselectedvalues");'."\n";
		print '		console.log(arrayofselectedvalues);'."\n";
		print '     console.log("Set the option to disabled for every entry that is currently selected somewhere else (so into arrayofselectedvalues)");'."\n";

		print '     $.each(arrayofselectedvalues, function(key, value) {'."\n";	// Loop on each selected value
		print '         if (value != -1) {'."\n";
		print '     		console.log("Process key="+key+" value="+value+" to disable.");'."\n";
		print '				$("select.targetselectchange").find(\'option[value="\'+value+\'"]:not(:selected)\').prop("disabled", true);'."\n";	// Set to disabled except if currently selected
		print '         }'."\n";
		print '     });'."\n";
		print '}'."\n";

		// Function to save the selection in database
		print 'function saveSelection() {'."\n";
		//print '		console.log(arrayofselectedvalues);'."\n";
		print '		arrayselectedfields = [];'."\n";
		print '		arrayselectedfields.push(0);'."\n";

		print '     $.each( arrayofselectedvalues, function( key, value ) {'."\n";
		print '         if (value != -1) {'."\n";
		print '				arrayselectedfields.push(value);'."\n";
		print '			} else {'."\n";
		print '				arrayselectedfields.push(0);'."\n";
		print '			}'."\n";
		print '		});'."\n";

		print "		$.ajax({\n";
		print "			type: 'POST',\n";
		print "			dataType: 'json',\n";
		print "			url: '".dol_escape_js($_SERVER["PHP_SELF"])."?action=saveselectorder&token=".newToken()."',\n";
		print "			data: 'selectorder='+arrayselectedfields.toString(),\n";
		print "			success: function(){\n";
		print "				console.log('The selected fields have been saved into '+arrayselectedfields.toString());\n";
		print "			},\n";
		print '		});'."\n";

		// Now we loop on all target fields that are mandatory to show if they are not mapped yet.
		print '     console.log("arrayselectedfields");';
		print '     console.log(arrayselectedfields);';
		print '     console.log("arrayoftargetmandatoryfields");';
		print '     console.log(arrayoftargetmandatoryfields);';
		print "     listtoshow = '';";
		print "     nbelement = arrayoftargetmandatoryfields.length
					for (let i = 0; i < nbelement; i++) {
						if (arrayoftargetmandatoryfields[i] && ! arrayselectedfields.includes(arrayoftargetmandatoryfields[i])) {
							console.log(arrayoftargetmandatoryfields[i]+' not mapped');
							listtoshow = listtoshow + (listtoshow ? ', ' : '') + '<b>' + arrayoftargetfields[i] + '*</b>';
						}
                    }
					console.log(listtoshow);
					if (listtoshow) {
						listtoshow = '".dol_escape_js(img_warning($langs->trans("MandatoryTargetFieldsNotMapped")).' '.$langs->trans("MandatoryTargetFieldsNotMapped")).": ' + listtoshow;
						$('#div-mandatory-target-fields-not-mapped').html(listtoshow);
					} else {
						$('#div-mandatory-target-fields-not-mapped').html('<span class=\"opacitymedium\">".dol_escape_js($langs->trans("AllTargetMandatoryFieldsAreMapped"))."</span>');
					}
		";

		print '}'."\n";

		// If we make a change on a selectbox
		print '$(".targetselectchange").change(function(){'."\n";
		print '     setOptionsToDisabled();'."\n";

		print '		if(previousselectedlabelimport != "" && previousselectedvalueimport != -1) {'."\n";
		print '			let valuetochange = $(this).val(); '."\n";
		print '			$(".boxtdunused").each(function(){'."\n";
		print '				if ($(this).text().includes(valuetochange)){'."\n";
		print '					arraychild = $(this)[0].childNodes'."\n";
		print '					arraytexttomodify = arraychild[0].textContent.split(" ")'."\n";
		print '					arraytexttomodify[1] = previousselectedvalueimport '."\n";
		print '					textmodified = arraytexttomodify.join(" ") '."\n";
		print '					arraychild[0].textContent = textmodified'."\n";
		print '					arraychild[1].innerHTML = previousselectedlabelimport'."\n";
		print '				}'."\n";
		print '			})'."\n";
		print '		}'."\n";
		print '		$(this).blur()'."\n";

		print '		saveSelection()'."\n";
		print '});'."\n";

		print '})'."\n";
		print '</script>'."\n";
	}

	/*
	 * Action bar
	 */
	print '<div class="tabsAction">';

	if (count($array_match_file_to_database)) {
		if ($mandatoryfieldshavesource) {
			print '<a class="butAction saveorderselect" href="import.php?step=5'.$param.'&filetoimport='.urlencode($filetoimport).'">'.$langs->trans("NextStep").'</a>';
		} else {
			print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("SomeMandatoryFieldHaveNoSource")).'">'.$langs->trans("NextStep").'</a>';
		}
	}

	print '</div>';


	// Area for profils import
	if (count($array_match_file_to_database)) {
		print '<br>'."\n";
		print '<!-- Area to add new import profile -->'."\n";
		print '<div class="marginbottomonly"><span class="opacitymedium">'.$langs->trans("SaveImportModel").'</span></div>';

		print '<form class="nocellnopadd" action="'.$_SERVER["PHP_SELF"].'" method="post">';
		print '<input type="hidden" name="token" value="'.newToken().'">';
		print '<input type="hidden" name="action" value="add_import_model">';
		print '<input type="hidden" name="step" value="'.$step.'">';
		print '<input type="hidden" name="format" value="'.$format.'">';
		print '<input type="hidden" name="datatoimport" value="'.$datatoimport.'">';
		print '<input type="hidden" name="filetoimport" value="'.$filetoimport.'">';
		print '<input type="hidden" name="hexa" value="'.$hexa.'">';
		print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
		print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
		print '<input type="hidden" name="page_y" value="">';
		print '<input type="hidden" value="'.dol_escape_htmltag($separator).'" name="separator">';
		print '<input type="hidden" value="'.dol_escape_htmltag($enclosure).'" name="enclosure">';

		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
		print '<table summary="selectofimportprofil" class="noborder centpercent">';
		print '<tr class="liste_titre">';
		print '<td>'.$langs->trans("ImportModelName").'</td>';
		print '<td>'.$langs->trans("Visibility").'</td>';
		print '<td></td>';
		print '</tr>';

		$nameofimportprofile = str_replace(' ', '-', $langs->trans("ImportProfile").' '.$titleofmodule.' '.dol_print_date(dol_now('gmt'), 'dayxcard'));
		if (GETPOST('import_name')) {	// If we have submitted a form, we take value used for the update try
			$nameofimportprofile = $import_name;
		}

		print '<tr class="oddeven">';
		print '<td><input name="import_name" class="minwidth300" value="'.$nameofimportprofile.'"></td>';
		print '<td>';
		$arrayvisibility = array('private' => $langs->trans("Private"), 'all' => $langs->trans("Everybody"));
		print $form->selectarray('visibility', $arrayvisibility, 'private');
		print '</td>';
		print '<td class="right">';
		print '<input type="submit" class="button smallpaddingimp reposition" value="'.$langs->trans("SaveImportProfile").'">';
		print '</td></tr>';

		// List of existing import profils
		$sql = "SELECT rowid, label, fk_user, entity";
		$sql .= " FROM ".MAIN_DB_PREFIX."import_model";
		$sql .= " WHERE type = '".$db->escape($datatoimport)."'";
		if (!getDolGlobalString('EXPORTS_SHARE_MODELS')) {	// EXPORTS_SHARE_MODELS means all templates are visible, whatever is owner.
			$sql .= " AND fk_user IN (0, ".((int) $user->id).")";
		}
		$sql .= " ORDER BY rowid";

		$resql = $db->query($sql);
		if ($resql) {
			$num = $db->num_rows($resql);

			$tmpuser = new User($db);

			$i = 0;
			while ($i < $num) {
				$obj = $db->fetch_object($resql);

				print '<tr class="oddeven"><td>';
				print $obj->label;
				print '</td>';
				print '<td class="tdoverflowmax150">';
				if (empty($obj->fk_user)) {
					print $langs->trans("Everybody");
				} else {
					$tmpuser->fetch($obj->fk_user);
					print $tmpuser->getNomUrl(-1);
				}
				print '</td>';
				print '<td class="right">';
				print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?step='.$step.$param.'&action=deleteprof&token='.newToken().'&id='.$obj->rowid.'&filetoimport='.urlencode($filetoimport).'">';
				print img_delete();
				print '</a>';
				print '</tr>';
				$i++;
			}
		} else {
			dol_print_error($db);
		}

		print '</table>';
		print '</div>';

		print '</form>';
	}
}

// STEP 5: Summary of choices and launch simulation
if ($step == 5 && $datatoimport) {
	$max_execution_time_for_importexport = getDolGlobalInt('IMPORT_MAX_EXECUTION_TIME', 300); // 5mn if not defined
	$max_time = @ini_get("max_execution_time");
	if ($max_time && $max_time < $max_execution_time_for_importexport) {
		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.");
		@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
	}

	$model = $format;
	$list = $objmodelimport->listOfAvailableImportFormat($db);

	// Create class to use for import
	$dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
	$file = "import_".$model.".modules.php";
	$classname = "Import".ucfirst($model);
	require_once $dir.$file;
	$obj = new $classname($db, $datatoimport);
	'@phan-var-force ModeleImports $obj';
	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		$obj->separator = $separator_used;
		$obj->enclosure = $enclosure;
	}

	// Load source fields in input file
	$fieldssource = array();
	$result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport);

	if ($result >= 0) {
		// Read first line
		$arrayrecord = $obj->import_read_record();
		// Put into array fieldssource starting with 1.
		$i = 1;
		foreach ($arrayrecord as $key => $val) {
			$fieldssource[$i]['example1'] = dol_trunc($val['val'], 24);
			$i++;
		}
		$obj->import_close_file();
	}

	$nboflines = $obj->import_get_nb_of_lines($conf->import->dir_temp.'/'.$filetoimport);

	$param = '&leftmenu=import&format='.urlencode($format).'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport).'&nboflines='.((int) $nboflines).'&separator='.urlencode($separator).'&enclosure='.urlencode($enclosure);
	$param2 = $param; // $param2 = $param without excludefirstline and endatlinenb
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if (!empty($updatekeys)) {
		$param .= '&updatekeys[]='.implode('&updatekeys[]=', $updatekeys);
	}

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 5);


	print '<form action="'.$_SERVER["PHP_SELF"].'?'.$param2.'" method="POST">';
	print '<input type="hidden" name="token" value="'.newToken().'">';
	print '<input type="hidden" name="step" value="5">'; // step 5
	print '<input type="hidden" name="action" value="launchsimu">'; // step 5

	print dol_get_fiche_head($head, 'step5', 'Import', -2, 'upload');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table width="100%" class="border tableforfield">';

	// Module
	print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
	print '<td>';
	$titleofmodule = $objimport->array_import_module[0]['module']->getName();
	// Special case for import common to module/services
	if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
		$titleofmodule = $langs->trans("ProductOrService");
	}
	print $titleofmodule;
	print '</td></tr>';

	// Lot de donnees a importer
	print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
	print '<td>';
	$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
	$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
	print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
	print $objimport->array_import_label[0];
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';
	print '<table width="100%" class="border tableforfield">';

	// Source file format
	print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
	print '<td class="nowraponall">';
	$text = $objmodelimport->getDriverDescForKey($format);
	// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
	print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
	print '</td></tr>';

	// Separator and enclosure
	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
		print '<td>';
		print $langs->trans("Separator").' : '.dol_escape_htmltag($separator);
		print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : '.dol_escape_htmltag($enclosure);
		print '</td></tr>';
	}

	// File to import
	print '<tr><td>'.$langs->trans("FileToImport").'</td>';
	print '<td>';
	$modulepart = 'import';
	$relativepath = GETPOST('filetoimport');
	print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
	print img_mime($file, '', 'pictofixedwidth');
	print $filetoimport;
	print img_picto($langs->trans("Download"), 'download', 'class="paddingleft opacitymedium"');
	print '</a>';
	print '</td></tr>';

	// Total lines in source file
	print '<tr><td>';
	print $langs->trans("NbOfSourceLines");
	print '</td><td>';
	print $nboflines;
	print '</td></tr>';

	// Range of lines to import
	print '<tr><td>';
	print $langs->trans("ImportFromToLine");
	print '</td><td>';
	if ($action == 'launchsimu') {
		print '<input type="number" class="maxwidth50 right" name="excludefirstlinebis" disabled="disabled" value="'.$excludefirstline.'">';
		print '<input type="hidden" name="excludefirstline" value="'.$excludefirstline.'">';
	} else {
		print '<input type="number" class="maxwidth50 right" name="excludefirstline" value="'.$excludefirstline.'">';
		print $form->textwithpicto("", $langs->trans("SetThisValueTo2ToExcludeFirstLine"));
	}
	print ' - ';
	if ($action == 'launchsimu') {
		print '<input type="text" class="maxwidth50" name="endatlinenbbis" disabled="disabled" value="'.$endatlinenb.'">';
		print '<input type="hidden" name="endatlinenb" value="'.$endatlinenb.'">';
	} else {
		print '<input type="text" class="maxwidth50" name="endatlinenb" value="'.$endatlinenb.'">';
		print $form->textwithpicto("", $langs->trans("KeepEmptyToGoToEndOfFile"));
	}
	if ($action == 'launchsimu') {
		print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'?step=5'.$param.'">'.$langs->trans("Modify").'</a>';
	}
	if ($excludefirstline == 2) {
		print $form->textwithpicto("", $langs->trans("WarningFirstImportedLine", $excludefirstline), 1, 'warning', "warningexcludefirstline");
		print '<script>
			$( document ).ready(function() {
				$("input[name=\'excludefirstline\']").on("change",function(){
					if($(this).val() <= 1){
						$(".warningexcludefirstline").hide();
					}else{
						$(".warningexcludefirstline").show();
					}
				})
			});
		</script>';
	}
	print '</td></tr>';

	// Keys for data UPDATE (not INSERT of new data)
	print '<tr><td>';
	print $form->textwithpicto($langs->trans("KeysToUseForUpdates"), $langs->trans("SelectPrimaryColumnsForUpdateAttempt"));
	print '</td><td>';
	if ($action == 'launchsimu') {
		if (count($updatekeys)) {
			print $form->multiselectarray('updatekeysbis', $objimport->array_import_updatekeys[0], $updatekeys, 0, 0, '', 1, '80%', 'disabled');
		} else {
			print '<span class="opacitymedium">'.$langs->trans("NoUpdateAttempt").'</span> &nbsp; -';
		}
		foreach ($updatekeys as $val) {
			print '<input type="hidden" name="updatekeys[]" value="'.$val.'">';
		}
		print ' &nbsp; <a href="'.$_SERVER["PHP_SELF"].'?step=5'.$param.'">'.$langs->trans("Modify").'</a>';
	} else {
		if (is_array($objimport->array_import_updatekeys[0]) && count($objimport->array_import_updatekeys[0])) {   //TODO dropdown UL is created inside nested SPANS
			print $form->multiselectarray('updatekeys', $objimport->array_import_updatekeys[0], $updatekeys, 0, 0, '', 1, '80%');
			//print $form->textwithpicto("", $langs->trans("SelectPrimaryColumnsForUpdateAttempt"));
		} else {
			print '<span class="opacitymedium">'.$langs->trans("UpdateNotYetSupportedForThisImport").'</span>';
		}
	}
	/*echo '<pre>';
	print_r($objimport->array_import_updatekeys);
	echo '</pre>';*/
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print load_fiche_titre($langs->trans("InformationOnTargetTables"), '', 'file-import');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table class="centpercent border tableforfield">';

	// Tables imported
	print '<tr><td class="titlefieldcreate">';
	print $langs->trans("TablesTarget");
	print '</td><td>';
	$listtables = array();
	$sort_array_match_file_to_database = $array_match_file_to_database;
	foreach ($array_match_file_to_database as $code => $label) {
		//var_dump($fieldssource);
		if ($code > count($fieldssource)) {
			continue;
		}
		//print $code.'-'.$label;
		$alias = preg_replace('/(\..*)$/i', '', $label);
		$listtables[$alias] = $objimport->array_import_tables[0][$alias];
	}
	if (count($listtables)) {
		$newval = '';
		//ksort($listtables);
		foreach ($listtables as $val) {
			if ($newval) {
				print ', ';
			}
			$newval = $val;
			// Link to Dolibarr wiki pages
			/*$helppagename='EN:Table_'.$newval;
			if ($helppagename && empty($conf->global->MAIN_HELP_DISABLELINK))
			{
				// Get helpbaseurl, helppage and mode from helppagename and langs
				$arrayres=getHelpParamFor($helppagename,$langs);
				$helpbaseurl=$arrayres['helpbaseurl'];
				$helppage=$arrayres['helppage'];
				$mode=$arrayres['mode'];
				$newval.=' <a href="'.sprintf($helpbaseurl,$helppage).'">'.img_picto($langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage'),DOL_URL_ROOT.'/theme/common/helpdoc.png','',1).'</a>';
			}*/
			print $newval;
		}
	} else {
		print $langs->trans("Error");
	}
	print '</td></tr>';

	// Fields imported
	print '<tr><td>';
	print $langs->trans("FieldsTarget").'</td><td class="small">';
	$listfields = array();
	$i = 0;
	//print 'fieldsource='.$fieldssource;
	$sort_array_match_file_to_database = $array_match_file_to_database;
	ksort($sort_array_match_file_to_database);
	//var_dump($sort_array_match_file_to_database);
	foreach ($sort_array_match_file_to_database as $code => $label) {
		$i++;
		//var_dump($fieldssource);
		if ($code > count($fieldssource)) {
			continue;
		}
		//print $code.'-'.$label;
		$alias = preg_replace('/(\..*)$/i', '', $label);
		$listfields[$i] = '<span class="nowrap">'.$langs->trans("Column").' '.num2Alpha((int) $code - 1).' -> '.$label.'</span>';
	}
	print count($listfields) ? (implode(', ', $listfields)) : $langs->trans("Error");
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print dol_get_fiche_end();


	if ($action != 'launchsimu') {
		// Show import id
		print '<br><span class="opacitymedium">';
		print $langs->trans("NowClickToTestTheImport", $langs->transnoentitiesnoconv("RunSimulateImportFile")).'</span><br>';
		print '<br>';

		// Actions
		print '<div class="center">';
		if ($user->hasRight('import', 'run')) {
			print '<input type="submit" class="butAction" value="'.$langs->trans("RunSimulateImportFile").'">';
		} else {
			print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunSimulateImportFile").'</a>';
		}
		print '</div>';
	} else {
		// Launch import
		$arrayoferrors = array();
		$arrayofwarnings = array();
		$maxnboferrors = getDolGlobalInt('IMPORT_MAX_NB_OF_ERRORS', 50);
		$maxnbofwarnings = getDolGlobalInt('IMPORT_MAX_NB_OF_WARNINGS', 50);
		$nboferrors = 0;
		$nbofwarnings = 0;

		$importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');

		//var_dump($array_match_file_to_database);

		$db->begin();

		// Open input file
		$nbok = 0;
		$pathfile = $conf->import->dir_temp.'/'.$filetoimport;
		$result = $obj->import_open_file($pathfile);
		if ($result > 0) {
			global $tablewithentity_cache;
			$tablewithentity_cache = array();
			$sourcelinenb = 0;
			$endoffile = 0;

			// Loop on each input file record
			while (($sourcelinenb < $nboflines) && !$endoffile) {
				$sourcelinenb++;
				// Read line and store it into $arrayrecord
				//dol_syslog("line ".$sourcelinenb.' - '.$nboflines.' - '.$excludefirstline.' - '.$endatlinenb);
				$arrayrecord = $obj->import_read_record();
				if ($arrayrecord === false) {
					$arrayofwarnings[$sourcelinenb][0] = array('lib' => $langs->trans('ErrorFileLinesReachEOF', $nboflines, $sourcelinenb), 'type' => 'EOF_RECORD_ON_SEVERAL_LINES');
					$endoffile++;
					continue;
				}
				if ($excludefirstline && ($sourcelinenb < $excludefirstline)) {
					continue;
				}
				if ($endatlinenb && ($sourcelinenb > $endatlinenb)) {
					break;
				}

				$parameters = array(
					'step'                         => $step,
					'datatoimport'                 => $datatoimport,
					'obj'                          => &$obj,
					'arrayrecord'                  => $arrayrecord,
					'array_match_file_to_database' => $array_match_file_to_database,
					'objimport'                    => $objimport,
					'fieldssource'                 => $fieldssource,
					'importid'                     => $importid,
					'updatekeys'                   => $updatekeys,
					'arrayoferrors'                => &$arrayoferrors,
					'arrayofwarnings'              => &$arrayofwarnings,
					'nbok'                         => &$nbok,
				);

				$reshook = $hookmanager->executeHooks('ImportInsert', $parameters);
				if ($reshook < 0) {
					$arrayoferrors[$sourcelinenb][] = [
						'lib' => implode("<br>", array_merge([$hookmanager->error], $hookmanager->errors))
					];
				}

				if (empty($reshook)) {
					// Run import
					$result = $obj->import_insert($arrayrecord, $array_match_file_to_database, $objimport, count($fieldssource), $importid, $updatekeys);

					if (count($obj->errors)) {
						$arrayoferrors[$sourcelinenb] = $obj->errors;
					}
					if (count($obj->warnings)) {
						$arrayofwarnings[$sourcelinenb] = $obj->warnings;
					}
					if (!count($obj->errors) && !count($obj->warnings)) {
						$nbok++;
					}
				}

				$reshook = $hookmanager->executeHooks('AfterImportInsert', $parameters);
				if ($reshook < 0) {
					$arrayoferrors[$sourcelinenb][] = [
						'lib' => implode("<br>", array_merge([$hookmanager->error], $hookmanager->errors))
					];
				}
			}
			// Close file
			$obj->import_close_file();
		} else {
			print $langs->trans("ErrorFailedToOpenFile", $pathfile);
		}

		$error = 0;

		// Run the sql after import if defined
		//var_dump($objimport->array_import_run_sql_after[0]);
		if (!empty($objimport->array_import_run_sql_after[0]) && is_array($objimport->array_import_run_sql_after[0])) {
			$i = 0;
			foreach ($objimport->array_import_run_sql_after[0] as $sqlafterimport) {
				$i++;
				$resqlafterimport = $db->query($sqlafterimport);
				if (!$resqlafterimport) {
					$arrayoferrors['none'][] = array('lib' => $langs->trans("Error running final request: ".$sqlafterimport));
					$error++;
				}
			}
		}

		$db->rollback(); // We force rollback because this was just a simulation.

		// Show OK
		if (!count($arrayoferrors) && !count($arrayofwarnings)) {
			print '<br>';
			print '<div class="info">';
			print '<div class=""><b>'.$langs->trans("ResultOfSimulationNoError").'</b></div>';
			print $langs->trans("NbInsertSim", empty($obj->nbinsert) ? 0 : $obj->nbinsert).'<br>';
			print $langs->trans("NbUpdateSim", empty($obj->nbupdate) ? 0 : $obj->nbupdate).'<br>';
			print '</div>';
			print '<br>';
		} else {
			print '<br>';
			print '<div class="warning">';
			print $langs->trans("NbOfLinesOK", $nbok).'...<br>';
			print '</div>';
			print '<br>';
		}

		// Show Errors
		//var_dump($arrayoferrors);
		if (count($arrayoferrors)) {
			print img_error().' <b>'.$langs->trans("ErrorsOnXLines", count($arrayoferrors)).'</b><br>';
			print '<table width="100%" class="border"><tr><td>';
			foreach ($arrayoferrors as $key => $val) {
				$nboferrors++;
				if ($nboferrors > $maxnboferrors) {
					print $langs->trans("TooMuchErrors", (count($arrayoferrors) - $nboferrors))."<br>";
					break;
				}
				print '* '.$langs->trans("Line").' '.dol_escape_htmltag($key).'<br>';
				foreach ($val as $i => $err) {
					print ' &nbsp; &nbsp; > '.dol_escape_htmltag($err['lib']).'<br>';
				}
			}
			print '</td></tr></table>';
			print '<br>';
		}

		// Show Warnings
		//var_dump($arrayoferrors);
		if (count($arrayofwarnings)) {
			print img_warning().' <b>'.$langs->trans("WarningsOnXLines", count($arrayofwarnings)).'</b><br>';
			print '<table width="100%" class="border"><tr><td>';
			foreach ($arrayofwarnings as $key => $val) {
				$nbofwarnings++;
				if ($nbofwarnings > $maxnbofwarnings) {
					print $langs->trans("TooMuchWarnings", (count($arrayofwarnings) - $nbofwarnings))."<br>";
					break;
				}
				print ' * '.$langs->trans("Line").' '.dol_escape_htmltag((string) $key).'<br>';
				foreach ($val as $i => $err) {
					print ' &nbsp; &nbsp; > '.dol_escape_htmltag($err['lib']).'<br>';
				}
			}
			print '</td></tr></table>';
			print '<br>';
		}

		// Show import id
		$importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');

		print '<div class="center">';
		print '<span class="opacitymedium">'.$langs->trans("NowClickToRunTheImport", $langs->transnoentitiesnoconv("RunImportFile")).'</span><br>';
		/*if (empty($nboferrors)) {
			print $langs->trans("DataLoadedWithId", $importid).'<br>';
		}*/
		print '</div>';

		print '<br>';

		// Actions
		print '<div class="center">';
		if ($user->hasRight('import', 'run')) {
			if (empty($nboferrors)) {
				print '<a class="butAction" href="'.DOL_URL_ROOT.'/imports/import.php?leftmenu=import&step=6&importid='.$importid.$param.'">'.$langs->trans("RunImportFile").'</a>';
			} else {
				//print '<input type="submit" class="butAction" value="'.dol_escape_htmltag($langs->trans("RunSimulateImportFile")).'">';

				print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("CorrectErrorBeforeRunningImport")).'">'.$langs->trans("RunImportFile").'</a>';
			}
		} else {
			print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunSimulateImportFile").'</a>';

			print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions")).'">'.$langs->trans("RunImportFile").'</a>';
		}
		print '</div>';
	}

	print '</form>';
}


// STEP 6: Real import
if ($step == 6 && $datatoimport) {
	$max_execution_time_for_importexport = getDolGlobalInt('IMPORT_MAX_EXECUTION_TIME', 300); // 5mn if not defined
	$max_time = @ini_get("max_execution_time");
	if ($max_time && $max_time < $max_execution_time_for_importexport) {
		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.");
		@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
	}

	$model = $format;
	$list = $objmodelimport->listOfAvailableImportFormat($db);
	$importid = GETPOST("importid", 'alphanohtml');


	// Create class to use for import
	$dir = DOL_DOCUMENT_ROOT."/core/modules/import/";
	$file = "import_".$model.".modules.php";
	$classname = "Import".ucfirst($model);
	require_once $dir.$file;
	$obj = new $classname($db, $datatoimport);
	'@phan-var-force ModeleImports $obj';
	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		$obj->separator = $separator_used;
		$obj->enclosure = $enclosure;
	}

	// Load source fields in input file
	$fieldssource = array();
	$result = $obj->import_open_file($conf->import->dir_temp.'/'.$filetoimport);
	if ($result >= 0) {
		// Read first line
		$arrayrecord = $obj->import_read_record();
		// Put into array fieldssource starting with 1.
		$i = 1;
		foreach ($arrayrecord as $key => $val) {
			$fieldssource[$i]['example1'] = dol_trunc($val['val'], 24);
			$i++;
		}
		$obj->import_close_file();
	}

	$nboflines = (GETPOSTISSET("nboflines") ? GETPOSTINT("nboflines") : dol_count_nb_of_line($conf->import->dir_temp.'/'.$filetoimport));

	$param = '&format='.$format.'&datatoimport='.urlencode($datatoimport).'&filetoimport='.urlencode($filetoimport).'&nboflines='.((int) $nboflines);
	if ($excludefirstline) {
		$param .= '&excludefirstline='.urlencode($excludefirstline);
	}
	if ($endatlinenb) {
		$param .= '&endatlinenb='.urlencode($endatlinenb);
	}
	if ($separator) {
		$param .= '&separator='.urlencode($separator);
	}
	if ($enclosure) {
		$param .= '&enclosure='.urlencode($enclosure);
	}

	llxHeader('', $langs->trans("NewImport"), $help_url);

	$head = import_prepare_head($param, 6);

	print dol_get_fiche_head($head, 'step6', 'Import', -1, 'upload');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';

	print '<table width="100%" class="border">';

	// Module
	print '<tr><td class="titlefieldcreate">'.$langs->trans("Module").'</td>';
	print '<td>';
	$titleofmodule = $objimport->array_import_module[0]['module']->getName();
	// Special case for import common to module/services
	if (in_array($objimport->array_import_code[0], array('produit_supplierprices', 'produit_multiprice', 'produit_languages'))) {
		$titleofmodule = $langs->trans("ProductOrService");
	}
	print $titleofmodule;
	print '</td></tr>';

	// Lot de donnees a importer
	print '<tr><td>'.$langs->trans("DatasetToImport").'</td>';
	print '<td>';
	$entity = preg_replace('/:.*$/', '', $objimport->array_import_icon[0]);
	$entityicon = strtolower(!empty($entitytoicon[$entity]) ? $entitytoicon[$entity] : $entity);
	print img_object($objimport->array_import_module[0]['module']->getName(), $entityicon).' ';
	print $objimport->array_import_label[0];
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print load_fiche_titre($langs->trans("InformationOnSourceFile"), '', 'file-export');

	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';
	print '<table width="100%" class="border tableforfield">';

	// Source file format
	print '<tr><td class="titlefieldcreate">'.$langs->trans("SourceFileFormat").'</td>';
	print '<td class="nowraponall">';
	$text = $objmodelimport->getDriverDescForKey($format);
	// @phan-suppress-next-line PhanPluginSuspiciousParamPosition
	print $form->textwithpicto($objmodelimport->getDriverLabelForKey($format), $text);
	print '</td></tr>';

	// Separator and enclosure
	if ($model == 'csv') {
		'@phan-var-force ImportCsv $obj';
		print '<tr><td>'.$langs->trans("CsvOptions").'</td>';
		print '<td>';
		print $langs->trans("Separator").' : ';
		print htmlentities($separator);
		print '&nbsp;&nbsp;&nbsp;&nbsp;'.$langs->trans("Enclosure").' : ';
		print htmlentities($enclosure);
		print '</td></tr>';
	}

	// File to import
	print '<tr><td>'.$langs->trans("FileToImport").'</td>';
	print '<td>';
	$modulepart = 'import';
	$relativepath = GETPOST('filetoimport');
	print '<a data-ajax="false" href="'.DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&file='.urlencode($relativepath).'&step=4'.$param.'" target="_blank" rel="noopener noreferrer">';
	print img_mime($file, '', 'pictofixedwidth');
	print $filetoimport;
	print '</a>';
	print '</td></tr>';

	// Nb of fields
	print '<tr><td>';
	print $langs->trans("NbOfSourceLines");
	print '</td><td>';
	print $nboflines;
	print '</td></tr>';

	// Do not import first lines
	print '<tr><td>';
	print $langs->trans("ImportFromLine");
	print '</td><td>';
	print '<input type="text" size="4" name="excludefirstline" disabled="disabled" value="'.$excludefirstline.'">';
	print '</td></tr>';

	// Do not import end lines
	print '<tr><td>';
	print $langs->trans("EndAtLineNb");
	print '</td><td>';
	print '<input type="text" size="4" name="endatlinenb" disabled="disabled" value="'.$endatlinenb.'">';
	print '</td></tr>';

	print '</table>';
	print '</div>';

	print '<br>';

	print '<b>'.$langs->trans("InformationOnTargetTables").'</b>';
	print '<div class="underbanner clearboth"></div>';
	print '<div class="fichecenter">';
	print '<table class="border centpercent">';

	// Tables imported
	print '<tr><td width="25%">';
	print $langs->trans("TablesTarget");
	print '</td><td>';
	$listtables = array();
	foreach ($array_match_file_to_database as $code => $label) {
		//var_dump($fieldssource);
		if ($code > count($fieldssource)) {
			continue;
		}
		//print $code.'-'.$label;
		$alias = preg_replace('/(\..*)$/i', '', $label);
		$listtables[$alias] = $objimport->array_import_tables[0][$alias];
	}
	if (count($listtables)) {
		$newval = '';
		foreach ($listtables as $val) {
			if ($newval) {
				print ', ';
			}
			$newval = $val;
			// Link to Dolibarr wiki pages
			/*$helppagename='EN:Table_'.$newval;
			if ($helppagename && empty($conf->global->MAIN_HELP_DISABLELINK))
			{
				// Get helpbaseurl, helppage and mode from helppagename and langs
				$arrayres=getHelpParamFor($helppagename,$langs);
				$helpbaseurl=$arrayres['helpbaseurl'];
				$helppage=$arrayres['helppage'];
				$mode=$arrayres['mode'];
				$newval.=' <a href="'.sprintf($helpbaseurl,$helppage).'">'.img_picto($langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage'),DOL_URL_ROOT.'/theme/common/helpdoc.png','',1).'</a>';
			}*/
			print $newval;
		}
	} else {
		print $langs->trans("Error");
	}
	print '</td></tr>';

	// Fields imported
	print '<tr><td>';
	print $langs->trans("FieldsTarget").'</td><td>';
	$listfields = array();
	$i = 0;
	$sort_array_match_file_to_database = $array_match_file_to_database;
	ksort($sort_array_match_file_to_database);
	//var_dump($sort_array_match_file_to_database);
	foreach ($sort_array_match_file_to_database as $code => $label) {
		$i++;
		//var_dump($fieldssource);
		if ($code > count($fieldssource)) {
			continue;
		}
		//print $code.'-'.$label;
		$alias = preg_replace('/(\..*)$/i', '', $label);
		$listfields[$i] = $langs->trans("Field").' '.$code.'->'.$label;
	}
	print count($listfields) ? (implode(', ', $listfields)) : $langs->trans("Error");
	print '</td></tr>';

	print '</table>';
	print '</div>';

	// Launch import
	$arrayoferrors = array();
	$arrayofwarnings = array();
	$maxnboferrors = !getDolGlobalString('IMPORT_MAX_NB_OF_ERRORS') ? 50 : $conf->global->IMPORT_MAX_NB_OF_ERRORS;
	$maxnbofwarnings = !getDolGlobalString('IMPORT_MAX_NB_OF_WARNINGS') ? 50 : $conf->global->IMPORT_MAX_NB_OF_WARNINGS;
	$nboferrors = 0;
	$nbofwarnings = 0;

	$importid = dol_print_date(dol_now(), '%Y%m%d%H%M%S');

	//var_dump($array_match_file_to_database);

	$db->begin();

	// Open input file
	$nbok = 0;
	$pathfile = $conf->import->dir_temp.'/'.$filetoimport;
	$result = $obj->import_open_file($pathfile);
	if ($result > 0) {
		global $tablewithentity_cache;
		$tablewithentity_cache = array();
		$sourcelinenb = 0;
		$endoffile = 0;

		while ($sourcelinenb < $nboflines && !$endoffile) {
			$sourcelinenb++;
			$arrayrecord = $obj->import_read_record();
			if ($arrayrecord === false) {
				$arrayofwarnings[$sourcelinenb][0] = array('lib' => $langs->trans('ErrorFileLinesReachEOF', $nboflines, $sourcelinenb), 'type' => 'EOF_RECORD_ON_SEVERAL_LINES');
				$endoffile++;
				continue;
			}
			if ($excludefirstline && ($sourcelinenb < $excludefirstline)) {
				continue;
			}
			if ($endatlinenb && ($sourcelinenb > $endatlinenb)) {
				break;
			}

			$parameters = array(
				'step'                         => $step,
				'datatoimport'                 => $datatoimport,
				'obj'                          => &$obj,
				'arrayrecord'                  => $arrayrecord,
				'array_match_file_to_database' => $array_match_file_to_database,
				'objimport'                    => $objimport,
				'fieldssource'                 => $fieldssource,
				'importid'                     => $importid,
				'updatekeys'                   => $updatekeys,
				'arrayoferrors'                => &$arrayoferrors,
				'arrayofwarnings'              => &$arrayofwarnings,
				'nbok'                         => &$nbok,
			);

			$reshook = $hookmanager->executeHooks('ImportInsert', $parameters);
			if ($reshook < 0) {
				$arrayoferrors[$sourcelinenb][] = [
					'lib' => implode("<br>", array_merge([$hookmanager->error], $hookmanager->errors))
				];
			}

			if (empty($reshook)) {
				// Run import
				$result = $obj->import_insert($arrayrecord, $array_match_file_to_database, $objimport, count($fieldssource), $importid, $updatekeys);

				if (count($obj->errors)) {
					$arrayoferrors[$sourcelinenb] = $obj->errors;
				}
				if (count($obj->warnings)) {
					$arrayofwarnings[$sourcelinenb] = $obj->warnings;
				}

				if (!count($obj->errors) && !count($obj->warnings)) {
					$nbok++;
				}
			}

			$reshook = $hookmanager->executeHooks('AfterImportInsert', $parameters);
			if ($reshook < 0) {
				$arrayoferrors[$sourcelinenb][] = [
					'lib' => implode("<br>", array_merge([$hookmanager->error], $hookmanager->errors))
				];
			}
		}
		// Close file
		$obj->import_close_file();
	} else {
		print $langs->trans("ErrorFailedToOpenFile", $pathfile);
	}

	if (count($arrayoferrors) > 0) {
		$db->rollback(); // We force rollback because this was errors.
	} else {
		$error = 0;

		// Run the sql after import if defined
		//var_dump($objimport->array_import_run_sql_after[0]);
		if (!empty($objimport->array_import_run_sql_after[0]) && is_array($objimport->array_import_run_sql_after[0])) {
			$i = 0;
			foreach ($objimport->array_import_run_sql_after[0] as $sqlafterimport) {
				$i++;
				$resqlafterimport = $db->query($sqlafterimport);
				if (!$resqlafterimport) {
					$arrayoferrors['none'][] = array('lib' => $langs->trans("Error running final request: ".$sqlafterimport));
					$error++;
				}
			}
		}

		if (!$error) {
			$db->commit(); // We can commit if no errors.
		} else {
			$db->rollback();
		}
	}

	print dol_get_fiche_end();


	// Show result
	print '<br>';
	print '<div class="info">';
	print $langs->trans("NbOfLinesImported", $nbok).'</b><br>';
	print $langs->trans("NbInsert", empty($obj->nbinsert) ? 0 : $obj->nbinsert).'<br>';
	print $langs->trans("NbUpdate", empty($obj->nbupdate) ? 0 : $obj->nbupdate).'<br>';
	print '</div>';
	print '<div class="center">';
	print $langs->trans("FileWasImported", $importid).'<br>';
	print '<span class="opacitymedium">'.$langs->trans("YouCanUseImportIdToFindRecord", $importid).'</span><br>';
	print '</div>';
}



print '<br>';

// End of page
llxFooter();
$db->close();


/**
 * Function to put the movable box of a source field
 *
 * @param	array<int|string,array{label?:string,example1?:string,required?:bool,imported?:bool|int<0,1>,position?:int}>		$fieldssource	List of source fields
 * @param	int		$pos			Pos
 * @param	string	$key			Key
 * @return	void
 */
function show_elem($fieldssource, $pos, $key)
{
	global $conf, $langs;

	$height = '32px';

	if ($key == 'none') {
		//stop multiple duplicate ids with no number
		print "\n\n<!-- Box_no-key start-->\n";
		print '<div class="box boximport" style="padding:0;">'."\n";
		print '<table summary="boxtable_no-key" class="centpercent nobordernopadding">'."\n";
	} else {
		print "\n\n<!-- Box ".$pos." start -->\n";
		print '<div class="box boximport" style="padding: 0;" id="boxto_'.$pos.'">'."\n";

		print '<table summary="boxtable'.$pos.'" class="nobordernopadding centpercent tableimport">'."\n";
	}

	if (($pos && $pos > count($fieldssource)) && (!isset($fieldssource[$pos]["imported"]))) {	// No fields
		/*
		print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
		print '<td class="nocellnopadd" width="16" style="font-weight: normal">';
		print '</td>';
		print '<td style="font-weight: normal">';
		print $langs->trans("NoFields");
		print '</td>';
		print '</tr>';
		*/
	} elseif ($key == 'none') {	// Empty line
		print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
		print '<td class="nocellnopadd" width="16" style="font-weight: normal">';
		print '&nbsp;';
		print '</td>';
		print '<td style="font-weight: normal">';
		print '&nbsp;';
		print '</td>';
		print '</tr>';
	} else {
		// Print field of source file
		print '<tr style="height:'.$height.'" class="trimport oddevenimport">';
		print '<td class="nocellnopadd" width="16" style="font-weight: normal">';
		// 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
		//print img_picto($langs->trans("MoveField", $pos), 'grip_title', 'class="boxhandle" style="cursor:move;"');
		print img_picto($langs->trans("Column").' '.num2Alpha($pos - 1), 'file', 'class="pictofixedwidth marginleftonly"');
		print '</td>';
		if (isset($fieldssource[$pos]['imported']) && $fieldssource[$pos]['imported'] == false) {
			print '<td class="nowraponall boxtdunused" style="font-weight: normal">';
		} else {
			print '<td class="nowraponall tdoverflowmax500" style="font-weight: normal">';
		}
		print $langs->trans("Column").' '.num2Alpha($pos - 1).' (#'.$pos.')';
		if (empty($fieldssource[$pos]['example1'])) {
			$example = $fieldssource[$pos]['label'];
		} else {
			$example = $fieldssource[$pos]['example1'];
		}
		if ($example) {
			if (!utf8_check($example)) {
				$example = mb_convert_encoding($example, 'UTF-8', 'ISO-8859-1');
			}
			// if (!empty($conf->dol_optimize_smallscreen)) { //print '<br>'; }
			print ' - ';
			print '<i class="opacitymedium">'.dol_escape_htmltag($example).'</i>';
		}
		print '</td>';
		print '</tr>';
	}

	print "</table>\n";

	print "</div>\n";
	print "<!-- Box end -->\n\n";
}


/**
 * Return not used field number
 *
 * @param 	array<int,mixed|mixed[]>	$fieldssource	Array of field source
 * @param	array<int,mixed|mixed[]>	$listofkey		Array of keys
 * @return	int
 */
function getnewkey(&$fieldssource, &$listofkey)
{
	$i = count($fieldssource) + 1;
	// Max number of key
	$maxkey = 0;
	foreach ($listofkey as $key => $val) {
		$maxkey = max($maxkey, $key);
	}
	// Found next empty key
	while ($i <= $maxkey) {
		if (empty($listofkey[$i])) {
			break;
		} else {
			$i++;
		}
	}

	$listofkey[$i] = 1;
	return $i;
}
/**
 * Return array with element inserted in it at position $position
 *
 * @param	array<int|string,array{label?:string,example1?:string,required?:bool,imported?:bool|int<0,1>,position?:int}>		$array			Array of field source
 * @param	int		$position		key of position to insert to
 * @param	array{label?:string,example1?:string,required?:bool,imported?:bool|int<0,1>,position?:int}		$insertArray	Array to insert
 * @return	array<int|string,array{label?:string,example1?:string,required?:bool,imported?:bool|int<0,1>,position?:int}>
 */
function arrayInsert($array, $position, $insertArray)
{
	$ret = [];

	if ($position == count($array)) {
		$ret = $array + $insertArray;
	} else {
		$i = 0;
		foreach ($array as $key => $value) {
			if ($position == $i++) {
				$ret += $insertArray;
			}

			$ret[$key] = $value;
		}
	}

	return $ret;
}