import.php 91 KB

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