repair.php 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592
  1. <?php
  2. /* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  6. * Copyright (C) 2021 Frédéric France <frederic.france@free.fr>
  7. * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/install/repair.php
  24. * \brief Run repair script
  25. */
  26. include_once 'inc.php';
  27. if (file_exists($conffile)) {
  28. include_once $conffile;
  29. }
  30. require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php';
  31. include_once $dolibarr_main_document_root.'/core/lib/images.lib.php';
  32. require_once $dolibarr_main_document_root.'/core/class/extrafields.class.php';
  33. require_once 'lib/repair.lib.php';
  34. $step = 2;
  35. $ok = 0;
  36. // Cette page peut etre longue. On augmente le delai autorise.
  37. // Ne fonctionne que si on est pas en safe_mode.
  38. $err = error_reporting();
  39. error_reporting(0);
  40. @set_time_limit(120);
  41. error_reporting($err);
  42. $setuplang = GETPOST("selectlang", 'aZ09', 3) ?GETPOST("selectlang", 'aZ09', 3) : 'auto';
  43. $langs->setDefaultLang($setuplang);
  44. $langs->loadLangs(array("admin", "install", "other"));
  45. if ($dolibarr_main_db_type == "mysqli") {
  46. $choix = 1;
  47. }
  48. if ($dolibarr_main_db_type == "pgsql") {
  49. $choix = 2;
  50. }
  51. if ($dolibarr_main_db_type == "mssql") {
  52. $choix = 3;
  53. }
  54. dolibarr_install_syslog("--- repair: entering upgrade.php page");
  55. if (!is_object($conf)) {
  56. dolibarr_install_syslog("repair: conf file not initialized", LOG_ERR);
  57. }
  58. /*
  59. * View
  60. */
  61. pHeader('', "upgrade2", GETPOST('action', 'aZ09'));
  62. // Action to launch the repair script
  63. $actiondone = 1;
  64. print '<h3>'.$langs->trans("Repair").'</h3>';
  65. print 'Option standard (\'test\' or \'confirmed\') is '.(GETPOST('standard', 'alpha') ?GETPOST('standard', 'alpha') : 'undefined').'<br>'."\n";
  66. // Disable modules
  67. print 'Option force_disable_of_modules_not_found (\'test\' or \'confirmed\') is '.(GETPOST('force_disable_of_modules_not_found', 'alpha') ?GETPOST('force_disable_of_modules_not_found', 'alpha') : 'undefined').'<br>'."\n";
  68. // Files
  69. print 'Option restore_thirdparties_logos (\'test\' or \'confirmed\') is '.(GETPOST('restore_thirdparties_logos', 'alpha') ?GETPOST('restore_thirdparties_logos', 'alpha') : 'undefined').'<br>'."\n";
  70. print 'Option restore_user_pictures (\'test\' or \'confirmed\') is '.(GETPOST('restore_user_pictures', 'alpha') ?GETPOST('restore_user_pictures', 'alpha') : 'undefined').'<br>'."\n";
  71. print 'Option rebuild_product_thumbs (\'test\' or \'confirmed\') is '.(GETPOST('rebuild_product_thumbs', 'alpha') ?GETPOST('rebuild_product_thumbs', 'alpha') : 'undefined').'<br>'."\n";
  72. // Clean tables and data
  73. print 'Option clean_linked_elements (\'test\' or \'confirmed\') is '.(GETPOST('clean_linked_elements', 'alpha') ?GETPOST('clean_linked_elements', 'alpha') : 'undefined').'<br>'."\n";
  74. print 'Option clean_menus (\'test\' or \'confirmed\') is '.(GETPOST('clean_menus', 'alpha') ?GETPOST('clean_menus', 'alpha') : 'undefined').'<br>'."\n";
  75. print 'Option clean_orphelin_dir (\'test\' or \'confirmed\') is '.(GETPOST('clean_orphelin_dir', 'alpha') ?GETPOST('clean_orphelin_dir', 'alpha') : 'undefined').'<br>'."\n";
  76. print 'Option clean_product_stock_batch (\'test\' or \'confirmed\') is '.(GETPOST('clean_product_stock_batch', 'alpha') ?GETPOST('clean_product_stock_batch', 'alpha') : 'undefined').'<br>'."\n";
  77. print 'Option clean_perm_table (\'test\' or \'confirmed\') is '.(GETPOST('clean_perm_table', 'alpha') ?GETPOST('clean_perm_table', 'alpha') : 'undefined').'<br>'."\n";
  78. print 'Option repair_link_dispatch_lines_supplier_order_lines, (\'test\' or \'confirmed\') is '.(GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha') ?GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha') : 'undefined').'<br>'."\n";
  79. // Init data
  80. print 'Option set_empty_time_spent_amount (\'test\' or \'confirmed\') is '.(GETPOST('set_empty_time_spent_amount', 'alpha') ?GETPOST('set_empty_time_spent_amount', 'alpha') : 'undefined').'<br>'."\n";
  81. // Structure
  82. print 'Option force_utf8_on_tables (force utf8 + row=dynamic), for mysql/mariadb only (\'test\' or \'confirmed\') is '.(GETPOST('force_utf8_on_tables', 'alpha') ?GETPOST('force_utf8_on_tables', 'alpha') : 'undefined').'<br>'."\n";
  83. print "Option force_utf8mb4_on_tables (force utf8mb4 + row=dynamic, EXPERIMENTAL!), for mysql/mariadb only ('test' or 'confirmed') is ".(GETPOST('force_utf8mb4_on_tables', 'alpha') ? GETPOST('force_utf8mb4_on_tables', 'alpha') : 'undefined')."<br>\n";
  84. // Rebuild sequence
  85. print 'Option rebuild_sequences, for postgresql only (\'test\' or \'confirmed\') is '.(GETPOST('rebuild_sequences', 'alpha') ?GETPOST('rebuild_sequences', 'alpha') : 'undefined').'<br>'."\n";
  86. print '<br>';
  87. print '<table cellspacing="0" cellpadding="1" border="0" width="100%">';
  88. $error = 0;
  89. // If password is encoded, we decode it
  90. if (preg_match('/crypted:/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
  91. require_once $dolibarr_main_document_root.'/core/lib/security.lib.php';
  92. if (preg_match('/crypted:/i', $dolibarr_main_db_pass)) {
  93. $dolibarr_main_db_pass = preg_replace('/crypted:/i', '', $dolibarr_main_db_pass);
  94. $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_pass);
  95. $dolibarr_main_db_encrypted_pass = $dolibarr_main_db_pass; // We need to set this as it is used to know the password was initially crypted
  96. } else {
  97. $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
  98. }
  99. }
  100. // $conf is already instancied inside inc.php
  101. $conf->db->type = $dolibarr_main_db_type;
  102. $conf->db->host = $dolibarr_main_db_host;
  103. $conf->db->port = $dolibarr_main_db_port;
  104. $conf->db->name = $dolibarr_main_db_name;
  105. $conf->db->user = $dolibarr_main_db_user;
  106. $conf->db->pass = $dolibarr_main_db_pass;
  107. // For encryption
  108. $conf->db->dolibarr_main_db_encryption = isset($dolibarr_main_db_encryption) ? $dolibarr_main_db_encryption : '';
  109. $conf->db->dolibarr_main_db_cryptkey = isset($dolibarr_main_db_cryptkey) ? $dolibarr_main_db_cryptkey : '';
  110. $db = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, (int) $conf->db->port);
  111. if ($db->connected) {
  112. print '<tr><td class="nowrap">';
  113. print $langs->trans("ServerConnection")." : $dolibarr_main_db_host</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
  114. dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerConnection").": ".$dolibarr_main_db_host.$langs->transnoentities("OK"));
  115. $ok = 1;
  116. } else {
  117. print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->transnoentities("Error")."</td></tr>";
  118. dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
  119. $ok = 0;
  120. }
  121. if ($ok) {
  122. if ($db->database_selected) {
  123. print '<tr><td class="nowrap">';
  124. print $langs->trans("DatabaseConnection")." : ".$dolibarr_main_db_name."</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
  125. dolibarr_install_syslog("repair: database connection successful: ".$dolibarr_main_db_name);
  126. $ok = 1;
  127. } else {
  128. print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->trans("Error")."</td></tr>";
  129. dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
  130. $ok = 0;
  131. }
  132. }
  133. // Show database version
  134. if ($ok) {
  135. $version = $db->getVersion();
  136. $versionarray = $db->getVersionArray();
  137. print '<tr><td>'.$langs->trans("ServerVersion").'</td>';
  138. print '<td class="right">'.$version.'</td></tr>';
  139. dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerVersion").": ".$version);
  140. //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
  141. }
  142. $conf->setValues($db);
  143. // Reset forced setup after the setValues
  144. if (defined('SYSLOG_FILE')) {
  145. $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
  146. }
  147. $conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
  148. /* Start action here */
  149. $oneoptionset = 0;
  150. $oneoptionset = (GETPOST('standard', 'alpha') || GETPOST('restore_thirdparties_logos', 'alpha') || GETPOST('clean_linked_elements', 'alpha') || GETPOST('clean_menus', 'alpha')
  151. || GETPOST('clean_orphelin_dir', 'alpha') || GETPOST('clean_product_stock_batch', 'alpha') || GETPOST('set_empty_time_spent_amount', 'alpha') || GETPOST('rebuild_product_thumbs', 'alpha')
  152. || GETPOST('clean_perm_table', 'alpha')
  153. || GETPOST('force_disable_of_modules_not_found', 'alpha')
  154. || GETPOST('force_utf8_on_tables', 'alpha') || GETPOST('force_utf8mb4_on_tables', 'alpha')
  155. || GETPOST('rebuild_sequences', 'alpha'));
  156. if ($ok && $oneoptionset) {
  157. // Show wait message
  158. print '<tr><td colspan="2">'.$langs->trans("PleaseBePatient").'<br><br></td></tr>';
  159. flush();
  160. }
  161. // run_sql: Run repair SQL file
  162. if ($ok && GETPOST('standard', 'alpha')) {
  163. $dir = "mysql/migration/";
  164. $filelist = array();
  165. $i = 0;
  166. $ok = 0;
  167. // Recupere list fichier
  168. $filesindir = array();
  169. $handle = opendir($dir);
  170. if (is_resource($handle)) {
  171. while (($file = readdir($handle)) !== false) {
  172. if (preg_match('/\.sql$/i', $file)) {
  173. $filesindir[] = $file;
  174. }
  175. }
  176. }
  177. sort($filesindir);
  178. foreach ($filesindir as $file) {
  179. if (preg_match('/repair/i', $file)) {
  180. $filelist[] = $file;
  181. }
  182. }
  183. // Loop on each file
  184. foreach ($filelist as $file) {
  185. print '<tr><td class="nowrap">*** ';
  186. print $langs->trans("Script").'</td><td class="right">'.$file.'</td></tr>';
  187. $name = substr($file, 0, dol_strlen($file) - 4);
  188. // Run sql script
  189. $ok = run_sql($dir.$file, 0, '', 1);
  190. }
  191. }
  192. // sync_extrafields: Search list of fields declared and list of fields created into databases, then create fields missing
  193. if ($ok && GETPOST('standard', 'alpha')) {
  194. $extrafields = new ExtraFields($db);
  195. $listofmodulesextra = array('societe'=>'societe', 'adherent'=>'adherent', 'product'=>'product',
  196. 'socpeople'=>'socpeople', 'propal'=>'propal', 'commande'=>'commande', 'facture'=>'facture',
  197. 'supplier_proposal'=>'supplier_proposal', 'commande_fournisseur'=>'commande_fournisseur', 'facture_fourn'=>'facture_fourn',
  198. 'actioncomm'=>'actioncomm', 'bom_bom'=>'bom_bom', 'mrp_mo'=>'mrp_mo',
  199. 'adherent_type'=>'adherent_type', 'user'=>'user', 'projet'=>'projet', 'projet_task'=>'projet_task');
  200. print '<tr><td colspan="2"><br>*** Check fields into extra table structure match table of definition. If not add column into table</td></tr>';
  201. foreach ($listofmodulesextra as $tablename => $elementtype) {
  202. // Get list of fields
  203. $tableextra = MAIN_DB_PREFIX.$tablename.'_extrafields';
  204. // Define $arrayoffieldsdesc
  205. $arrayoffieldsdesc = $extrafields->fetch_name_optionals_label($elementtype);
  206. // Define $arrayoffieldsfound
  207. $arrayoffieldsfound = array();
  208. $resql = $db->DDLDescTable($tableextra);
  209. if ($resql) {
  210. print '<tr><td>Check availability of extra field for '.$tableextra."<br>\n";
  211. $i = 0;
  212. while ($obj = $db->fetch_object($resql)) {
  213. $fieldname = $fieldtype = '';
  214. if (preg_match('/mysql/', $db->type)) {
  215. $fieldname = $obj->Field;
  216. $fieldtype = $obj->Type;
  217. } else {
  218. $fieldname = isset($obj->Key) ? $obj->Key : $obj->attname;
  219. $fieldtype = isset($obj->Type) ? $obj->Type : 'varchar';
  220. }
  221. if (empty($fieldname)) {
  222. continue;
  223. }
  224. if (in_array($fieldname, array('rowid', 'tms', 'fk_object', 'import_key'))) {
  225. continue;
  226. }
  227. $arrayoffieldsfound[$fieldname] = array('type'=>$fieldtype);
  228. }
  229. // If it does not match, we create fields
  230. foreach ($arrayoffieldsdesc as $code => $label) {
  231. if (!in_array($code, array_keys($arrayoffieldsfound))) {
  232. print 'Found field '.$code.' declared into '.MAIN_DB_PREFIX.'extrafields table but not found into desc of table '.$tableextra." -> ";
  233. $type = $extrafields->attributes[$elementtype]['type'][$code]; $length = $extrafields->attributes[$elementtype]['size'][$code]; $attribute = ''; $default = ''; $extra = ''; $null = 'null';
  234. if ($type == 'boolean') {
  235. $typedb = 'int';
  236. $lengthdb = '1';
  237. } elseif ($type == 'price') {
  238. $typedb = 'double';
  239. $lengthdb = '24,8';
  240. } elseif ($type == 'phone') {
  241. $typedb = 'varchar';
  242. $lengthdb = '20';
  243. } elseif ($type == 'mail') {
  244. $typedb = 'varchar';
  245. $lengthdb = '128';
  246. } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
  247. $typedb = 'text';
  248. $lengthdb = '';
  249. } elseif ($type == 'link') {
  250. $typedb = 'int';
  251. $lengthdb = '11';
  252. } else {
  253. $typedb = $type;
  254. $lengthdb = $length;
  255. }
  256. $field_desc = array(
  257. 'type'=>$typedb,
  258. 'value'=>$lengthdb,
  259. 'attribute'=>$attribute,
  260. 'default'=>$default,
  261. 'extra'=>$extra,
  262. 'null'=>$null
  263. );
  264. //var_dump($field_desc);exit;
  265. $result = 0;
  266. if (GETPOST('standard', 'alpha') == 'confirmed') {
  267. $result = $db->DDLAddField($tableextra, $code, $field_desc, "");
  268. if ($result < 0) {
  269. print "KO ".$db->lasterror."<br>\n";
  270. } else {
  271. print "OK<br>\n";
  272. }
  273. } else {
  274. print ' - Mode test, no column added.';
  275. }
  276. }
  277. }
  278. print "</td><td>&nbsp;</td></tr>\n";
  279. } else {
  280. dol_print_error($db);
  281. }
  282. }
  283. }
  284. // clean_data_ecm_dir: Clean data into ecm_directories table
  285. if ($ok && GETPOST('standard', 'alpha')) {
  286. clean_data_ecm_directories();
  287. }
  288. // clean declaration constants
  289. if ($ok && GETPOST('standard', 'alpha')) {
  290. print '<tr><td colspan="2"><br>*** Clean constant record of modules not enabled</td></tr>';
  291. $sql = "SELECT name, entity, value";
  292. $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
  293. $sql .= " WHERE name LIKE 'MAIN_MODULE_%_TPL' OR name LIKE 'MAIN_MODULE_%_CSS' OR name LIKE 'MAIN_MODULE_%_JS' OR name LIKE 'MAIN_MODULE_%_HOOKS'";
  294. $sql .= " OR name LIKE 'MAIN_MODULE_%_TRIGGERS' OR name LIKE 'MAIN_MODULE_%_THEME' OR name LIKE 'MAIN_MODULE_%_SUBSTITUTIONS' OR name LIKE 'MAIN_MODULE_%_MODELS'";
  295. $sql .= " OR name LIKE 'MAIN_MODULE_%_MENUS' OR name LIKE 'MAIN_MODULE_%_LOGIN' OR name LIKE 'MAIN_MODULE_%_BARCODE' OR name LIKE 'MAIN_MODULE_%_TABS_%'";
  296. $sql .= " OR name LIKE 'MAIN_MODULE_%_MODULEFOREXTERNAL'";
  297. $sql .= " ORDER BY name, entity";
  298. $resql = $db->query($sql);
  299. if ($resql) {
  300. $num = $db->num_rows($resql);
  301. if ($num) {
  302. $db->begin();
  303. $i = 0;
  304. while ($i < $num) {
  305. $obj = $db->fetch_object($resql);
  306. $reg = array();
  307. if (preg_match('/MAIN_MODULE_([^_]+)_(.+)/i', $obj->name, $reg)) {
  308. $name = $reg[1];
  309. $type = $reg[2];
  310. $sql2 = "SELECT COUNT(*) as nb";
  311. $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
  312. $sql2 .= " WHERE name = 'MAIN_MODULE_".$name."'";
  313. $sql2 .= " AND entity = ".((int) $obj->entity);
  314. $resql2 = $db->query($sql2);
  315. if ($resql2) {
  316. $obj2 = $db->fetch_object($resql2);
  317. if ($obj2 && $obj2->nb == 0) {
  318. // Module not found, so we can remove entry
  319. $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = '".$db->escape($obj->name)."' AND entity = ".((int) $obj->entity);
  320. if (GETPOST('standard', 'alpha') == 'confirmed') {
  321. $db->query($sqldelete);
  322. print '<tr><td>Widget '.$obj->name.' set in entity '.$obj->entity.' with value '.$obj->value.' -> Module '.$name.' not enabled in entity '.((int) $obj->entity).', we delete record</td></tr>';
  323. } else {
  324. print '<tr><td>Widget '.$obj->name.' set in entity '.$obj->entity.' with value '.$obj->value.' -> Module '.$name.' not enabled in entity '.((int) $obj->entity).', we should delete record (not done, mode test)</td></tr>';
  325. }
  326. } else {
  327. //print '<tr><td>Constant '.$obj->name.' set in entity '.$obj->entity.' with value '.$obj->value.' -> Module found in entity '.$obj->entity.', we keep record</td></tr>';
  328. }
  329. }
  330. }
  331. $i++;
  332. }
  333. $db->commit();
  334. }
  335. } else {
  336. dol_print_error($db);
  337. }
  338. }
  339. // clean box of not enabled modules
  340. if ($ok && GETPOST('standard', 'alpha')) {
  341. print '<tr><td colspan="2"><br>*** Clean definition of boxes of modules not enabled</td></tr>';
  342. $sql = "SELECT file, entity FROM ".MAIN_DB_PREFIX."boxes_def";
  343. $sql .= " WHERE file like '%@%'";
  344. $resql = $db->query($sql);
  345. if ($resql) {
  346. $num = $db->num_rows($resql);
  347. if ($num) {
  348. $db->begin();
  349. $i = 0;
  350. while ($i < $num) {
  351. $obj = $db->fetch_object($resql);
  352. $reg = array();
  353. if (preg_match('/^(.+)@(.+)$/i', $obj->file, $reg)) {
  354. $name = $reg[1];
  355. $module = $reg[2];
  356. $sql2 = "SELECT COUNT(*) as nb";
  357. $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
  358. $sql2 .= " WHERE name = 'MAIN_MODULE_".strtoupper($module)."'";
  359. $sql2 .= " AND entity = ".((int) $obj->entity);
  360. $sql2 .= " AND value <> 0";
  361. $resql2 = $db->query($sql2);
  362. if ($resql2) {
  363. $obj2 = $db->fetch_object($resql2);
  364. if ($obj2 && $obj2->nb == 0) {
  365. // Module not found, so we canremove entry
  366. $sqldeletea = "DELETE FROM ".MAIN_DB_PREFIX."boxes WHERE entity = ".((int) $obj->entity)." AND box_id IN (SELECT rowid FROM ".MAIN_DB_PREFIX."boxes_def WHERE file = '".$db->escape($obj->file)."' AND entity = ".((int) $obj->entity).")";
  367. $sqldeleteb = "DELETE FROM ".MAIN_DB_PREFIX."boxes_def WHERE file = '".$db->escape($obj->file)."' AND entity = ".((int) $obj->entity);
  368. if (GETPOST('standard', 'alpha') == 'confirmed') {
  369. $db->query($sqldeletea);
  370. $db->query($sqldeleteb);
  371. print '<tr><td>Constant '.$obj->file.' set in boxes_def for entity '.$obj->entity.' but MAIN_MODULE_'.strtoupper($module).' not defined in entity '.((int) $obj->entity).', we delete record</td></tr>';
  372. } else {
  373. print '<tr><td>Constant '.$obj->file.' set in boxes_def for entity '.$obj->entity.' but MAIN_MODULE_'.strtoupper($module).' not defined in entity '.((int) $obj->entity).', we should delete record (not done, mode test)</td></tr>';
  374. }
  375. } else {
  376. //print '<tr><td>Constant '.$obj->name.' set in entity '.$obj->entity.' with value '.$obj->value.' -> Module found in entity '.$obj->entity.', we keep record</td></tr>';
  377. }
  378. }
  379. }
  380. $i++;
  381. }
  382. $db->commit();
  383. }
  384. }
  385. }
  386. // restore_thirdparties_logos: Move logos to correct new directory.
  387. if ($ok && GETPOST('restore_thirdparties_logos')) {
  388. //$exts=array('gif','png','jpg');
  389. $ext = '';
  390. print '<tr><td colspan="2"><br>*** Restore thirdparties logo<br>';
  391. $sql = "SELECT s.rowid, s.nom as name, s.logo FROM ".MAIN_DB_PREFIX."societe as s ORDER BY s.nom";
  392. $resql = $db->query($sql);
  393. if ($resql) {
  394. $num = $db->num_rows($resql);
  395. $i = 0;
  396. while ($i < $num) {
  397. $obj = $db->fetch_object($resql);
  398. /*
  399. $name=preg_replace('/é/','',$obj->name);
  400. $name=preg_replace('/ /','_',$name);
  401. $name=preg_replace('/\'/','',$name);
  402. */
  403. $tmp = explode('.', $obj->logo);
  404. $name = $tmp[0];
  405. if (isset($tmp[1])) {
  406. $ext = '.'.$tmp[1];
  407. }
  408. if (!empty($name)) {
  409. $filetotest = $dolibarr_main_data_root.'/societe/logos/'.$name.$ext;
  410. $filetotestsmall = $dolibarr_main_data_root.'/societe/logos/thumbs/'.$name.'_small'.$ext;
  411. $exists = dol_is_file($filetotest);
  412. print 'Check thirdparty '.$obj->rowid.' name='.$obj->name.' logo='.$obj->logo.' file '.$filetotest." exists=".$exists."<br>\n";
  413. if ($exists) {
  414. $filetarget = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/'.$name.$ext;
  415. $filetargetsmall = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs/'.$name.'_small'.$ext;
  416. $existt = dol_is_file($filetarget);
  417. if (!$existt) {
  418. if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
  419. dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos');
  420. }
  421. print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
  422. if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
  423. dol_copy($filetotest, $filetarget, '', 0);
  424. }
  425. }
  426. $existtt = dol_is_file($filetargetsmall);
  427. if (!$existtt) {
  428. if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
  429. dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs');
  430. }
  431. print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
  432. if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
  433. dol_copy($filetotestsmall, $filetargetsmall, '', 0);
  434. }
  435. }
  436. }
  437. }
  438. $i++;
  439. }
  440. } else {
  441. $ok = 0;
  442. dol_print_error($db);
  443. }
  444. print '</td></tr>';
  445. }
  446. // restore_user_pictures: Move pictures to correct new directory.
  447. if ($ok && GETPOST('restore_user_pictures', 'alpha')) {
  448. //$exts=array('gif','png','jpg');
  449. $ext = '';
  450. print '<tr><td colspan="2"><br>*** Restore user pictures<br>';
  451. $sql = "SELECT s.rowid, s.firstname, s.lastname, s.login, s.photo FROM ".MAIN_DB_PREFIX."user as s ORDER BY s.rowid";
  452. $resql = $db->query($sql);
  453. if ($resql) {
  454. $num = $db->num_rows($resql);
  455. $i = 0;
  456. while ($i < $num) {
  457. $obj = $db->fetch_object($resql);
  458. /*
  459. $name=preg_replace('/é/','',$obj->name);
  460. $name=preg_replace('/ /','_',$name);
  461. $name=preg_replace('/\'/','',$name);
  462. */
  463. $tmp = explode('.', $obj->photo);
  464. $name = $tmp[0];
  465. if (isset($tmp[1])) {
  466. $ext = '.'.$tmp[1];
  467. }
  468. if (!empty($name)) {
  469. $filetotest = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/'.$name.$ext;
  470. $filetotestsmall = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_small'.$ext;
  471. $filetotestmini = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_mini'.$ext;
  472. $exists = dol_is_file($filetotest);
  473. print 'Check user '.$obj->rowid.' lastname='.$obj->lastname.' firstname='.$obj->firstname.' photo='.$obj->photo.' file '.$filetotest." exists=".$exists."<br>\n";
  474. if ($exists) {
  475. $filetarget = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/'.$name.$ext;
  476. $filetargetsmall = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_small'.$ext;
  477. $filetargetmini = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_mini'.$ext;
  478. $existt = dol_is_file($filetarget);
  479. if (!$existt) {
  480. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  481. dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid);
  482. }
  483. print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
  484. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  485. dol_copy($filetotest, $filetarget, '', 0);
  486. }
  487. }
  488. $existtt = dol_is_file($filetargetsmall);
  489. if (!$existtt) {
  490. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  491. dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
  492. }
  493. print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
  494. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  495. dol_copy($filetotestsmall, $filetargetsmall, '', 0);
  496. }
  497. }
  498. $existtt = dol_is_file($filetargetmini);
  499. if (!$existtt) {
  500. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  501. dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
  502. }
  503. print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestmini." -> ".$filetargetmini."<br>\n";
  504. if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
  505. dol_copy($filetotestmini, $filetargetmini, '', 0);
  506. }
  507. }
  508. }
  509. }
  510. $i++;
  511. }
  512. } else {
  513. $ok = 0;
  514. dol_print_error($db);
  515. }
  516. print '</td></tr>';
  517. }
  518. // rebuild_product_thumbs: Rebuild thumbs for product files
  519. if ($ok && GETPOST('rebuild_product_thumbs', 'alpha')) {
  520. $ext = '';
  521. global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
  522. print '<tr><td colspan="2"><br>*** Rebuild product thumbs<br>';
  523. $sql = "SELECT s.rowid, s.ref FROM ".MAIN_DB_PREFIX."product as s ORDER BY s.ref";
  524. $resql = $db->query($sql);
  525. if ($resql) {
  526. $num = $db->num_rows($resql);
  527. $i = 0;
  528. while ($i < $num) {
  529. $obj = $db->fetch_object($resql);
  530. if (!empty($obj->ref)) {
  531. $files = dol_dir_list($dolibarr_main_data_root.'/produit/'.$obj->ref, 'files', 0);
  532. foreach ($files as $file) {
  533. // Generate thumbs.
  534. if (image_format_supported($file['fullname']) == 1) {
  535. $imgThumbSmall = 'notbuild';
  536. if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
  537. // Used on logon for example
  538. $imgThumbSmall = vignette($file['fullname'], $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
  539. }
  540. print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbSmall." maxwidthsmall=".$maxwidthsmall." maxheightsmall=".$maxheightsmall."<br>\n";
  541. $imgThumbMini = 'notbuild';
  542. if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
  543. // Create mini thumbs for image (Ratio is near 16/9)
  544. // Used on menu or for setup page for example
  545. $imgThumbMini = vignette($file['fullname'], $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
  546. }
  547. print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbMini." maxwidthmini=".$maxwidthmini." maxheightmini=".$maxheightmini."<br>\n";
  548. }
  549. }
  550. }
  551. $i++;
  552. }
  553. } else {
  554. $ok = 0;
  555. dol_print_error($db);
  556. }
  557. print '</td></tr>';
  558. }
  559. // clean_linked_elements: Check and clean linked elements
  560. if ($ok && GETPOST('clean_linked_elements', 'alpha')) {
  561. print '<tr><td colspan="2"><br>*** Check table of linked elements and delete orphelins links</td></tr>';
  562. // propal => order
  563. print '<tr><td colspan="2">'.checkLinkedElements('propal', 'commande')."</td></tr>\n";
  564. // propal => invoice
  565. print '<tr><td colspan="2">'.checkLinkedElements('propal', 'facture')."</td></tr>\n";
  566. // order => invoice
  567. print '<tr><td colspan="2">'.checkLinkedElements('commande', 'facture')."</td></tr>\n";
  568. // order => shipping
  569. print '<tr><td colspan="2">'.checkLinkedElements('commande', 'shipping')."</td></tr>\n";
  570. // shipping => delivery
  571. print '<tr><td colspan="2">'.checkLinkedElements('shipping', 'delivery')."</td></tr>\n";
  572. // order_supplier => invoice_supplier
  573. print '<tr><td colspan="2">'.checkLinkedElements('order_supplier', 'invoice_supplier')."</td></tr>\n";
  574. }
  575. // clean_menus: Check orphelins menus
  576. if ($ok && GETPOST('clean_menus', 'alpha')) {
  577. print '<tr><td colspan="2"><br>*** Clean menu entries coming from disabled modules</td></tr>';
  578. $sql = "SELECT rowid, module";
  579. $sql .= " FROM ".MAIN_DB_PREFIX."menu as c";
  580. $sql .= " WHERE module IS NOT NULL AND module <> ''";
  581. $sql .= " ORDER BY module";
  582. $resql = $db->query($sql);
  583. if ($resql) {
  584. $num = $db->num_rows($resql);
  585. if ($num) {
  586. $i = 0;
  587. while ($i < $num) {
  588. $obj = $db->fetch_object($resql);
  589. $modulecond = $obj->module;
  590. $modulecondarray = explode('|', $obj->module); // Name of module
  591. print '<tr><td>';
  592. print $modulecond;
  593. $db->begin();
  594. if ($modulecond) { // And menu entry for module $modulecond was found in database.
  595. $moduleok = 0;
  596. foreach ($modulecondarray as $tmpname) {
  597. if ($tmpname == 'margins') {
  598. $tmpname = 'margin'; // TODO Remove this when normalized
  599. }
  600. $result = 0;
  601. if (!empty($conf->$tmpname)) {
  602. $result = $conf->$tmpname->enabled;
  603. }
  604. if ($result) {
  605. $moduleok++;
  606. }
  607. }
  608. if (!$moduleok && $modulecond) {
  609. print ' - Module condition '.$modulecond.' seems ko, we delete menu entry.';
  610. if (GETPOST('clean_menus') == 'confirmed') {
  611. $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."menu WHERE module = '".$db->escape($modulecond)."'";
  612. $resql2 = $db->query($sql2);
  613. if (!$resql2) {
  614. $error++;
  615. dol_print_error($db);
  616. } else {
  617. print ' - <span class="warning">Cleaned</span>';
  618. }
  619. } else {
  620. print ' - <span class="warning">Canceled (test mode)</span>';
  621. }
  622. } else {
  623. print ' - Module condition '.$modulecond.' is ok, we do nothing.';
  624. }
  625. }
  626. if (!$error) {
  627. $db->commit();
  628. } else {
  629. $db->rollback();
  630. }
  631. print'</td></tr>';
  632. if ($error) {
  633. break;
  634. }
  635. $i++;
  636. }
  637. } else {
  638. print '<tr><td>No menu entries of disabled menus found</td></tr>';
  639. }
  640. } else {
  641. dol_print_error($db);
  642. }
  643. }
  644. // clean_orphelin_dir: Run purge of directory
  645. if ($ok && GETPOST('clean_orphelin_dir', 'alpha')) {
  646. $listmodulepart = array('company', 'invoice', 'invoice_supplier', 'propal', 'order', 'order_supplier', 'contract', 'tax');
  647. foreach ($listmodulepart as $modulepart) {
  648. $filearray = array();
  649. $upload_dir = isset($conf->$modulepart->dir_output) ? $conf->$modulepart->dir_output : '';
  650. if ($modulepart == 'company') {
  651. $upload_dir = $conf->societe->dir_output; // TODO change for multicompany sharing
  652. }
  653. if ($modulepart == 'invoice') {
  654. $upload_dir = $conf->facture->dir_output;
  655. }
  656. if ($modulepart == 'invoice_supplier') {
  657. $upload_dir = $conf->fournisseur->facture->dir_output;
  658. }
  659. if ($modulepart == 'order') {
  660. $upload_dir = $conf->commande->dir_output;
  661. }
  662. if ($modulepart == 'order_supplier') {
  663. $upload_dir = $conf->fournisseur->commande->dir_output;
  664. }
  665. if ($modulepart == 'contract') {
  666. $upload_dir = $conf->contrat->dir_output;
  667. }
  668. if (empty($upload_dir)) {
  669. continue;
  670. }
  671. print '<tr><td colspan="2"><br>*** Clean orphelins files into files '.$upload_dir.'</td></tr>';
  672. $filearray = dol_dir_list($upload_dir, "files", 1, '', array('^SPECIMEN\.pdf$', '^\.', '(\.meta|_preview.*\.png)$', '^temp$', '^payments$', '^CVS$', '^thumbs$'), '', SORT_DESC, 1, true);
  673. // To show ref or specific information according to view to show (defined by $module)
  674. if ($modulepart == 'company') {
  675. include_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
  676. $object_instance = new Societe($db);
  677. }
  678. if ($modulepart == 'invoice') {
  679. include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  680. $object_instance = new Facture($db);
  681. } elseif ($modulepart == 'invoice_supplier') {
  682. include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
  683. $object_instance = new FactureFournisseur($db);
  684. } elseif ($modulepart == 'propal') {
  685. include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  686. $object_instance = new Propal($db);
  687. } elseif ($modulepart == 'order') {
  688. include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  689. $object_instance = new Commande($db);
  690. } elseif ($modulepart == 'order_supplier') {
  691. include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
  692. $object_instance = new CommandeFournisseur($db);
  693. } elseif ($modulepart == 'contract') {
  694. include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
  695. $object_instance = new Contrat($db);
  696. } elseif ($modulepart == 'tax') {
  697. include_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php';
  698. $object_instance = new ChargeSociales($db);
  699. }
  700. foreach ($filearray as $key => $file) {
  701. if (!is_dir($file['name'])
  702. && $file['name'] != '.'
  703. && $file['name'] != '..'
  704. && $file['name'] != 'CVS'
  705. ) {
  706. // Define relative path used to store the file
  707. $relativefile = preg_replace('/'.preg_quote($upload_dir.'/', '/').'/', '', $file['fullname']);
  708. //var_dump($file);
  709. $id = 0; $ref = ''; $object_instance->id = 0; $object_instance->ref = ''; $label = '';
  710. // To show ref or specific information according to view to show (defined by $module)
  711. if ($modulepart == 'invoice') {
  712. preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
  713. }
  714. if ($modulepart == 'invoice_supplier') {
  715. preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg); $id = empty($reg[1]) ? '' : $reg[1];
  716. }
  717. if ($modulepart == 'propal') {
  718. preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
  719. }
  720. if ($modulepart == 'order') {
  721. preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
  722. }
  723. if ($modulepart == 'order_supplier') {
  724. preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
  725. }
  726. if ($modulepart == 'contract') {
  727. preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
  728. }
  729. if ($modulepart == 'tax') {
  730. preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg); $id = $reg[1];
  731. }
  732. if ($id || $ref) {
  733. //print 'Fetch '.$id.' or '.$ref.'<br>';
  734. $result = $object_instance->fetch($id, $ref);
  735. //print $result.'<br>';
  736. if ($result == 0) { // Not found but no error
  737. // Clean of orphelins directories are done into repair.php
  738. print '<tr><td colspan="2">';
  739. print 'Delete orphelins file '.$file['fullname'].'<br>';
  740. if (GETPOST('clean_orphelin_dir', 'alpha') == 'confirmed') {
  741. dol_delete_file($file['fullname'], 1, 1, 1);
  742. dol_delete_dir(dirname($file['fullname']), 1);
  743. }
  744. print "</td></tr>";
  745. } elseif ($result < 0) {
  746. print 'Error in '.get_class($object_instance).'.fetch of id'.$id.' ref='.$ref.', result='.$result.'<br>';
  747. }
  748. }
  749. }
  750. }
  751. }
  752. }
  753. // clean_linked_elements: Check and clean linked elements
  754. if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) {
  755. $methodtofix = GETPOST('methodtofix', 'alpha') ?GETPOST('methodtofix', 'alpha') : 'updatestock';
  756. print '<tr><td colspan="2"><br>*** Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
  757. $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
  758. $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps LEFT JOIN ".MAIN_DB_PREFIX."product_batch as pb ON ps.rowid = pb.fk_product_stock";
  759. $sql .= " WHERE p.rowid = ps.fk_product";
  760. $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
  761. $sql .= " HAVING (SUM(pb.qty) IS NOT NULL AND reel != SUM(pb.qty)) OR (SUM(pb.qty) IS NULL AND p.tobatch > 0)";
  762. print $sql;
  763. $resql = $db->query($sql);
  764. if ($resql) {
  765. $num = $db->num_rows($resql);
  766. if ($num) {
  767. $i = 0;
  768. while ($i < $num) {
  769. $obj = $db->fetch_object($resql);
  770. print '<tr><td>Product '.$obj->rowid.'-'.$obj->ref.' in warehouse id='.$obj->fk_entrepot.' (product_stock.id='.$obj->psrowid.'): '.$obj->reel.' (Stock product_stock.reel) != '.($obj->reelbatch ? $obj->reelbatch : '0').' (Stock batch sum product_batch)';
  771. // Fix is required
  772. if ($obj->reel != $obj->reelbatch) {
  773. if (empty($obj->tobatch)) {
  774. // If product is not a product that support batches, we can clean stock by deleting the product batch lines
  775. print ' -> Delete qty '.$obj->reelbatch.' for any lot linked to fk_product_stock='.$obj->psrowid;
  776. $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."product_batch";
  777. $sql2 .= " WHERE fk_product_stock = ".((int) $obj->psrowid);
  778. print '<br>'.$sql2;
  779. if (GETPOST('clean_product_stock_batch') == 'confirmed') {
  780. $resql2 = $db->query($sql2);
  781. if (!$resql2) {
  782. $error++;
  783. dol_print_error($db);
  784. }
  785. }
  786. } else {
  787. if ($methodtofix == 'updatebatch') {
  788. // Method 1
  789. print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid;
  790. $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)";
  791. $sql2 .= "VALUES(".((int) $obj->psrowid).", '000000', ".((float) ($obj->reel - $obj->reelbatch)).")";
  792. print '<br>'.$sql2;
  793. if (GETPOST('clean_product_stock_batch') == 'confirmed') {
  794. $resql2 = $db->query($sql2);
  795. if (!$resql2) {
  796. // TODO If it fails, we must make update
  797. //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch";
  798. //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")";
  799. //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid)
  800. }
  801. }
  802. }
  803. if ($methodtofix == 'updatestock') {
  804. // Method 2
  805. print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid);
  806. $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock";
  807. $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid);
  808. print '<br>'.$sql2;
  809. if (GETPOST('clean_product_stock_batch') == 'confirmed') {
  810. $error = 0;
  811. $db->begin();
  812. $resql2 = $db->query($sql2);
  813. if ($resql2) {
  814. // We update product_stock, so we must fill p.stock into product too.
  815. $sql3 = 'UPDATE '.MAIN_DB_PREFIX.'product p SET p.stock= (SELECT SUM(ps.reel) FROM '.MAIN_DB_PREFIX.'product_stock ps WHERE ps.fk_product = p.rowid)';
  816. $resql3 = $db->query($sql3);
  817. if (!$resql3) {
  818. $error++;
  819. dol_print_error($db);
  820. }
  821. } else {
  822. $error++;
  823. dol_print_error($db);
  824. }
  825. if (!$error) {
  826. $db->commit();
  827. } else {
  828. $db->rollback();
  829. }
  830. }
  831. }
  832. }
  833. }
  834. print'</td></tr>';
  835. $i++;
  836. }
  837. } else {
  838. print '<tr><td colspan="2">Nothing to do</td></tr>';
  839. }
  840. } else {
  841. dol_print_error($db);
  842. }
  843. }
  844. // clean_product_stock_negative_if_batch
  845. if ($ok && GETPOST('clean_product_stock_negative_if_batch', 'alpha')) {
  846. print '<tr><td colspan="2"><br>Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
  847. $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
  848. $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product_batch as pb";
  849. $sql .= " WHERE p.rowid = ps.fk_product AND ps.rowid = pb.fk_product_stock";
  850. $sql .= " AND p.tobatch > 0";
  851. $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
  852. $sql .= " HAVING reel != SUM(pb.qty)";
  853. $resql = $db->query($sql);
  854. if ($resql) {
  855. $num = $db->num_rows($resql);
  856. if ($num) {
  857. $i = 0;
  858. while ($i < $num) {
  859. $obj = $db->fetch_object($resql);
  860. print '<tr><td>'.$obj->rowid.'-'.$obj->ref.'-'.$obj->fk_entrepot.' -> '.$obj->psrowid.': '.$obj->reel.' != '.$obj->reelbatch;
  861. // TODO
  862. }
  863. }
  864. }
  865. }
  866. // set_empty_time_spent_amount
  867. if ($ok && GETPOST('set_empty_time_spent_amount', 'alpha')) {
  868. print '<tr><td colspan="2"><br>*** Set value of time spent without amount</td></tr>';
  869. $sql = "SELECT COUNT(ptt.rowid) as nb, u.rowid as user_id, u.login, u.thm as user_thm";
  870. $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."user as u";
  871. $sql .= " WHERE ptt.fk_user = u.rowid";
  872. $sql .= " AND ptt.thm IS NULL and u.thm > 0";
  873. $sql .= " GROUP BY u.rowid, u.login, u.thm";
  874. $resql = $db->query($sql);
  875. if ($resql) {
  876. $num = $db->num_rows($resql);
  877. if ($num) {
  878. $i = 0;
  879. while ($i < $num) {
  880. $obj = $db->fetch_object($resql);
  881. print '<tr><td>'.$obj->login.'-'.$obj->user_id.' ('.$obj->nb.' lines to fix) -> '.$obj->user_thm;
  882. $db->begin();
  883. if (GETPOST('set_empty_time_spent_amount') == 'confirmed') {
  884. $sql2 = "UPDATE ".MAIN_DB_PREFIX."element_time";
  885. $sql2 .= " SET thm = ".$obj->user_thm." WHERE thm IS NULL AND fk_user = ".((int) $obj->user_id);
  886. $resql2 = $db->query($sql2);
  887. if (!$resql2) {
  888. $error++;
  889. dol_print_error($db);
  890. }
  891. }
  892. if (!$error) {
  893. $db->commit();
  894. } else {
  895. $db->rollback();
  896. }
  897. print'</td></tr>';
  898. if ($error) {
  899. break;
  900. }
  901. $i++;
  902. }
  903. } else {
  904. print '<tr><td>No time spent with empty line on users with a hourly rate defined</td></tr>';
  905. }
  906. } else {
  907. dol_print_error($db);
  908. }
  909. }
  910. // force_disable_of_modules_not_found
  911. if ($ok && GETPOST('force_disable_of_modules_not_found', 'alpha')) {
  912. print '<tr><td colspan="2"><br>*** Force modules not found physicaly to be disabled (only modules adding js, css or hooks can be detected as removed physicaly)</td></tr>';
  913. $arraylistofkey = array('hooks', 'js', 'css');
  914. foreach ($arraylistofkey as $key) {
  915. $sql = "SELECT DISTINCT name, value";
  916. $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
  917. $sql .= " WHERE name LIKE 'MAIN_MODULE_%_".strtoupper($key)."'";
  918. $sql .= " ORDER BY name";
  919. $resql = $db->query($sql);
  920. if ($resql) {
  921. $num = $db->num_rows($resql);
  922. if ($num) {
  923. $i = 0;
  924. while ($i < $num) {
  925. $obj = $db->fetch_object($resql);
  926. $constantname = $obj->name; // Name of constant for hook or js or css declaration
  927. print '<tr><td>';
  928. print dol_escape_htmltag($constantname);
  929. $db->begin();
  930. $reg = array();
  931. if (preg_match('/MAIN_MODULE_(.*)_'.strtoupper($key).'/i', $constantname, $reg)) {
  932. $name = strtolower($reg[1]);
  933. if ($name) { // An entry for key $key and module $name was found in database.
  934. $reloffile = '';
  935. $result = 'found';
  936. if ($key == 'hooks') {
  937. $reloffile = $name.'/class/actions_'.$name.'.class.php';
  938. }
  939. if ($key == 'js') {
  940. $value = $obj->value;
  941. $valuearray = json_decode($value);
  942. $reloffile = $valuearray[0];
  943. $reloffile = preg_replace('/^\//', '', $valuearray[0]);
  944. }
  945. if ($key == 'css') {
  946. $value = $obj->value;
  947. $valuearray = json_decode($value);
  948. if ($value && (!is_array($valuearray) || count($valuearray) == 0)) {
  949. $valuearray = array();
  950. $valuearray[0] = $value; // If value was not a json array but a string
  951. }
  952. $reloffile = preg_replace('/^\//', '', $valuearray[0]);
  953. }
  954. if ($reloffile) {
  955. //var_dump($key.' - '.$value.' - '.$reloffile);
  956. try {
  957. $result = dol_buildpath($reloffile, 0, 2);
  958. } catch (Exception $e) {
  959. $result = 'found'; // If error, we force like if we found to avoid any deletion
  960. }
  961. } else {
  962. $result = 'found'; //
  963. }
  964. if (!$result) {
  965. print ' - File of '.$key.' ('.$reloffile.') NOT found, we disable the module.';
  966. if (GETPOST('force_disable_of_modules_not_found') == 'confirmed') {
  967. $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."_".strtoupper($key)."'";
  968. $resql2 = $db->query($sql2);
  969. if (!$resql2) {
  970. $error++;
  971. dol_print_error($db);
  972. }
  973. $sql3 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."'";
  974. $resql3 = $db->query($sql3);
  975. if (!$resql3) {
  976. $error++;
  977. dol_print_error($db);
  978. } else {
  979. print ' - <span class="warning">Cleaned</span>';
  980. }
  981. } else {
  982. print ' - <span class="warning">Canceled (test mode)</span>';
  983. }
  984. } else {
  985. print ' - File of '.$key.' ('.$reloffile.') found, we do nothing.';
  986. }
  987. }
  988. if (!$error) {
  989. $db->commit();
  990. } else {
  991. $db->rollback();
  992. }
  993. }
  994. print'</td></tr>';
  995. if ($error) {
  996. break;
  997. }
  998. $i++;
  999. }
  1000. } else {
  1001. print '<tr><td>No active module with missing files found by searching on MAIN_MODULE_(.*)_'.strtoupper($key).'</td></tr>';
  1002. }
  1003. } else {
  1004. dol_print_error($db);
  1005. }
  1006. }
  1007. }
  1008. // clean_old_module_entries: Clean data into const when files of module were removed without being
  1009. if ($ok && GETPOST('clean_perm_table', 'alpha')) {
  1010. print '<tr><td colspan="2"><br>*** Clean table user_rights from lines of external modules no more enabled</td></tr>';
  1011. $listofmods = '';
  1012. foreach ($conf->modules as $key => $val) {
  1013. $listofmods .= ($listofmods ? ',' : '')."'".$db->escape($val)."'";
  1014. }
  1015. $sql = "SELECT id, libelle as label, module from ".MAIN_DB_PREFIX."rights_def WHERE module NOT IN (".$db->sanitize($listofmods, 1).") AND id > 100000";
  1016. $resql = $db->query($sql);
  1017. if ($resql) {
  1018. $num = $db->num_rows($resql);
  1019. if ($num) {
  1020. $i = 0;
  1021. while ($i < $num) {
  1022. $obj = $db->fetch_object($resql);
  1023. if ($obj->id > 0) {
  1024. print '<tr><td>Found line with id '.$obj->id.', label "'.$obj->label.'" of module "'.$obj->module.'" to delete';
  1025. if (GETPOST('clean_perm_table', 'alpha') == 'confirmed') {
  1026. $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."rights_def WHERE id = ".((int) $obj->id);
  1027. $resqldelete = $db->query($sqldelete);
  1028. if (!$resqldelete) {
  1029. dol_print_error($db);
  1030. }
  1031. print ' - deleted';
  1032. }
  1033. print '</td></tr>';
  1034. }
  1035. $i++;
  1036. }
  1037. } else {
  1038. print '<tr><td>No lines of a disabled external module (with id > 100000) found into table rights_def</td></tr>';
  1039. }
  1040. } else {
  1041. dol_print_error($db);
  1042. }
  1043. }
  1044. // force utf8 on tables
  1045. if ($ok && GETPOST('force_utf8_on_tables', 'alpha')) {
  1046. print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8/utf8_unicode_ci and row_format=dynamic (for mysql/mariadb only)</td></tr>';
  1047. if ($db->type == "mysql" || $db->type == "mysqli") {
  1048. $force_utf8_on_tables = GETPOST('force_utf8_on_tables', 'alpha');
  1049. $listoftables = $db->DDLListTablesFull($db->database_name);
  1050. // Disable foreign key checking for avoid errors
  1051. if ($force_utf8_on_tables == 'confirmed') {
  1052. $sql = 'SET FOREIGN_KEY_CHECKS=0';
  1053. print '<!-- '.$sql.' -->';
  1054. $resql = $db->query($sql);
  1055. }
  1056. foreach ($listoftables as $table) {
  1057. // do not convert llx_const if mysql encrypt/decrypt is used
  1058. if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
  1059. continue;
  1060. }
  1061. if ($table[1] == 'VIEW') {
  1062. print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
  1063. continue;
  1064. }
  1065. print '<tr><td colspan="2">';
  1066. print $table[0];
  1067. $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
  1068. $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci";
  1069. print '<!-- '.$sql1.' -->';
  1070. print '<!-- '.$sql2.' -->';
  1071. if ($force_utf8_on_tables == 'confirmed') {
  1072. $resql1 = $db->query($sql1);
  1073. if ($resql1) {
  1074. $resql2 = $db->query($sql2);
  1075. } else {
  1076. $resql2 = false;
  1077. }
  1078. print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
  1079. } else {
  1080. print ' - Disabled';
  1081. }
  1082. print '</td></tr>';
  1083. }
  1084. // Enable foreign key checking
  1085. if ($force_utf8_on_tables == 'confirmed') {
  1086. $sql = 'SET FOREIGN_KEY_CHECKS=1';
  1087. print '<!-- '.$sql.' -->';
  1088. $resql = $db->query($sql);
  1089. }
  1090. } else {
  1091. print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
  1092. }
  1093. }
  1094. // force utf8mb4 on tables EXPERIMENTAL !
  1095. if ($ok && GETPOST('force_utf8mb4_on_tables', 'alpha')) {
  1096. print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8mb4/utf8mb4_unicode_ci (for mysql/mariadb only)</td></tr>';
  1097. if ($db->type == "mysql" || $db->type == "mysqli") {
  1098. $force_utf8mb4_on_tables = GETPOST('force_utf8mb4_on_tables', 'alpha');
  1099. $listoftables = $db->DDLListTablesFull($db->database_name);
  1100. // Disable foreign key checking for avoid errors
  1101. if ($force_utf8mb4_on_tables == 'confirmed') {
  1102. $sql = 'SET FOREIGN_KEY_CHECKS=0';
  1103. print '<!-- '.$sql.' -->';
  1104. $resql = $db->query($sql);
  1105. }
  1106. foreach ($listoftables as $table) {
  1107. // do not convert llx_const if mysql encrypt/decrypt is used
  1108. if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
  1109. continue;
  1110. }
  1111. if ($table[1] == 'VIEW') {
  1112. print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
  1113. continue;
  1114. }
  1115. print '<tr><td colspan="2">';
  1116. print $table[0];
  1117. $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
  1118. $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
  1119. print '<!-- '.$sql1.' -->';
  1120. print '<!-- '.$sql2.' -->';
  1121. if ($force_utf8mb4_on_tables == 'confirmed') {
  1122. $resql1 = $db->query($sql1);
  1123. if ($resql1) {
  1124. $resql2 = $db->query($sql2);
  1125. } else {
  1126. $resql2 = false;
  1127. }
  1128. print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
  1129. } else {
  1130. print ' - Disabled';
  1131. }
  1132. print '</td></tr>';
  1133. flush();
  1134. ob_flush();
  1135. }
  1136. // Enable foreign key checking
  1137. if ($force_utf8mb4_on_tables == 'confirmed') {
  1138. $sql = 'SET FOREIGN_KEY_CHECKS=1';
  1139. print '<!-- '.$sql.' -->';
  1140. $resql = $db->query($sql);
  1141. }
  1142. } else {
  1143. print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
  1144. }
  1145. }
  1146. // rebuild sequences for pgsql
  1147. if ($ok && GETPOST('rebuild_sequences', 'alpha')) {
  1148. print '<tr><td colspan="2"><br>*** Force to rebuild sequences (for postgresql only)</td></tr>';
  1149. if ($db->type == "pgsql") {
  1150. $rebuild_sequence = GETPOST('rebuild_sequences', 'alpha');
  1151. if ($rebuild_sequence == 'confirmed') {
  1152. $sql = "SELECT dol_util_rebuild_sequences();";
  1153. print '<!-- '.$sql.' -->';
  1154. $resql = $db->query($sql);
  1155. }
  1156. } else {
  1157. print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
  1158. }
  1159. }
  1160. //
  1161. if ($ok && GETPOST('repair_link_dispatch_lines_supplier_order_lines')) {
  1162. /*
  1163. * This script is meant to be run when upgrading from a dolibarr version < 3.8
  1164. * to a newer version.
  1165. *
  1166. * Version 3.8 introduces a new column in llx_commande_fournisseur_dispatch, which
  1167. * matches the dispatch to a specific supplier order line (so that if there are
  1168. * several with the same product, the user can specifically tell which products of
  1169. * which line were dispatched where).
  1170. *
  1171. * However when migrating, the new column has a default value of 0, which means that
  1172. * old supplier orders whose lines were dispatched using the old dolibarr version
  1173. * have unspecific dispatch lines, which are not taken into account by the new version,
  1174. * thus making the order look like it was never dispatched at all.
  1175. *
  1176. * This scripts sets this foreign key to the first matching supplier order line whose
  1177. * product (and supplier order of course) are the same as the dispatch’s.
  1178. *
  1179. * If the dispatched quantity is more than indicated on the order line (this happens if
  1180. * there are several order lines for the same product), it creates new dispatch lines
  1181. * pointing to the other order lines accordingly, until all the dispatched quantity is
  1182. * accounted for.
  1183. */
  1184. $repair_link_dispatch_lines_supplier_order_lines = GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha');
  1185. echo '<tr><th>Repair llx_commande_fournisseur_dispatch.fk_commandefourndet</th></tr>';
  1186. echo '<tr><td>Repair in progress. This may take a while.</td></tr>';
  1187. $sql_dispatch = 'SELECT * FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch WHERE COALESCE(fk_commandefourndet, 0) = 0';
  1188. $db->begin();
  1189. $resql_dispatch = $db->query($sql_dispatch);
  1190. $n_processed_rows = 0;
  1191. $errors = array();
  1192. if ($resql_dispatch) {
  1193. if ($db->num_rows($resql_dispatch) == 0) {
  1194. echo '<tr><td>Nothing to do.</td></tr>';
  1195. exit;
  1196. }
  1197. while ($obj_dispatch = $db->fetch_object($resql_dispatch)) {
  1198. $sql_line = 'SELECT line.rowid, line.qty FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet AS line';
  1199. $sql_line .= ' WHERE line.fk_commande = '.((int) $obj_dispatch->fk_commande);
  1200. $sql_line .= ' AND line.fk_product = '.((int) $obj_dispatch->fk_product);
  1201. $resql_line = $db->query($sql_line);
  1202. // s’il y a plusieurs lignes avec le même produit sur cette commande fournisseur,
  1203. // on divise la ligne de dispatch en autant de lignes qu’on en a sur la commande pour le produit
  1204. // et on met la quantité de la ligne dans la limite du "budget" indiqué par dispatch.qty
  1205. $remaining_qty = $obj_dispatch->qty;
  1206. $first_iteration = true;
  1207. if (!$resql_line) {
  1208. echo '<tr><td>Unable to find a matching supplier order line for dispatch #'.$obj_dispatch->rowid.'</td></tr>';
  1209. $errors[] = $sql_line;
  1210. $n_processed_rows++;
  1211. continue;
  1212. }
  1213. if ($db->num_rows($resql_line) == 0) {
  1214. continue;
  1215. }
  1216. while ($obj_line = $db->fetch_object($resql_line)) {
  1217. if (!$remaining_qty) {
  1218. break;
  1219. }
  1220. if (!$obj_line->rowid) {
  1221. continue;
  1222. }
  1223. $qty_for_line = min($remaining_qty, $obj_line->qty);
  1224. if ($first_iteration) {
  1225. $sql_attach = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
  1226. $sql_attach .= ' SET fk_commandefourndet = '.((int) $obj_line->rowid).', qty = '.((float) $qty_for_line);
  1227. $sql_attach .= ' WHERE rowid = '.((int) $obj_dispatch->rowid);
  1228. $first_iteration = false;
  1229. } else {
  1230. $sql_attach_values = array(
  1231. ((int) $obj_dispatch->fk_commande),
  1232. ((int) $obj_dispatch->fk_product),
  1233. ((int) $obj_line->rowid),
  1234. ((float) $qty_for_line),
  1235. ((int) $obj_dispatch->fk_entrepot),
  1236. ((int) $obj_dispatch->fk_user),
  1237. $obj_dispatch->datec ? "'".$db->idate($db->jdate($obj_dispatch->datec))."'" : 'NULL',
  1238. $obj_dispatch->comment ? "'".$db->escape($obj_dispatch->comment)."'" : 'NULL',
  1239. $obj_dispatch->status ? ((int) $obj_dispatch->status) : 'NULL',
  1240. $obj_dispatch->tms ? "'".$db->idate($db->jdate($obj_dispatch->tms))."'" : 'NULL',
  1241. $obj_dispatch->batch ? "'".$db->escape($obj_dispatch->batch)."'" : 'NULL',
  1242. $obj_dispatch->eatby ? "'".$db->escape($obj_dispatch->eatby)."'" : 'NULL',
  1243. $obj_dispatch->sellby ? "'".$db->escape($obj_dispatch->sellby)."'" : 'NULL'
  1244. );
  1245. $sql_attach_values = join(', ', $sql_attach_values);
  1246. $sql_attach = 'INSERT INTO '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
  1247. $sql_attach .= ' (fk_commande, fk_product, fk_commandefourndet, qty, fk_entrepot, fk_user, datec, comment, status, tms, batch, eatby, sellby)';
  1248. $sql_attach .= " VALUES (".$sql_attach_values.")";
  1249. }
  1250. if ($repair_link_dispatch_lines_supplier_order_lines == 'confirmed') {
  1251. $resql_attach = $db->query($sql_attach);
  1252. } else {
  1253. $resql_attach = true; // Force success in test mode
  1254. }
  1255. if ($resql_attach) {
  1256. $remaining_qty -= $qty_for_line;
  1257. } else {
  1258. $errors[] = $sql_attach;
  1259. }
  1260. $first_iteration = false;
  1261. }
  1262. $n_processed_rows++;
  1263. // report progress every 256th row
  1264. if (!($n_processed_rows & 0xff)) {
  1265. echo '<tr><td>Processed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
  1266. flush();
  1267. ob_flush();
  1268. }
  1269. }
  1270. } else {
  1271. echo '<tr><td>Unable to find any dispatch without an fk_commandefourndet.'."</td></tr>\n";
  1272. echo $sql_dispatch."\n";
  1273. }
  1274. echo '<tr><td>Fixed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
  1275. echo '<tr><td>DONE.'."</td></tr>\n";
  1276. if (count($errors)) {
  1277. $db->rollback();
  1278. echo '<tr><td>The transaction was rolled back due to errors: nothing was changed by the script.</td></tr>';
  1279. } else {
  1280. $db->commit();
  1281. }
  1282. $db->close();
  1283. echo '<tr><td><h3>SQL queries with errors:</h3></tr></td>';
  1284. echo '<tr><td>'.join('</td></tr><tr><td>', $errors).'</td></tr>';
  1285. }
  1286. // Repair llx_commande_fournisseur to eleminate duplicate reference
  1287. if ($ok && GETPOST('repair_supplier_order_duplicate_ref')) {
  1288. require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php';
  1289. include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
  1290. $db->begin();
  1291. $err = 0;
  1292. // Query to find all duplicate supplier orders
  1293. $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
  1294. $sql .= " WHERE ref IN (SELECT cf.ref FROM " . MAIN_DB_PREFIX . "commande_fournisseur cf GROUP BY cf.ref, cf.entity HAVING COUNT(cf.rowid) > 1)";
  1295. // Build a list of ref => []CommandeFournisseur
  1296. $duplicateSupplierOrders = [];
  1297. $resql = $db->query($sql);
  1298. if ($resql) {
  1299. while ($rawSupplierOrder = $db->fetch_object($resql)) {
  1300. $supplierOrder = new CommandeFournisseur($db);
  1301. $supplierOrder->setVarsFromFetchObj($rawSupplierOrder);
  1302. $duplicateSupplierOrders[$rawSupplierOrder->ref] [] = $supplierOrder;
  1303. }
  1304. } else {
  1305. $err++;
  1306. }
  1307. // Process all duplicate supplier order and regenerate the reference for all except the first one
  1308. foreach ($duplicateSupplierOrders as $ref => $supplierOrders) {
  1309. /** @var CommandeFournisseur $supplierOrder */
  1310. foreach (array_slice($supplierOrders, 1) as $supplierOrder) {
  1311. // Definition of supplier order numbering model name
  1312. $soc = new Societe($db);
  1313. $soc->fetch($supplierOrder->fourn_id);
  1314. $newRef = $supplierOrder->getNextNumRef($soc);
  1315. $sql = "UPDATE " . MAIN_DB_PREFIX . "commande_fournisseur cf SET cf.ref = '" . $db->escape($newRef) . "' WHERE cf.rowid = " . (int) $supplierOrder->id;
  1316. if (!$db->query($sql)) {
  1317. $err++;
  1318. }
  1319. }
  1320. }
  1321. if ($err == 0) {
  1322. $db->commit();
  1323. } else {
  1324. $db->rollback();
  1325. }
  1326. }
  1327. print '</table>';
  1328. if (empty($actiondone)) {
  1329. print '<div class="error">'.$langs->trans("ErrorWrongParameters").'</div>';
  1330. }
  1331. if ($oneoptionset) {
  1332. print '<div class="center" style="padding-top: 10px"><a href="../index.php?mainmenu=home&leftmenu=home'.(GETPOSTISSET("login") ? '&username='.urlencode(GETPOST("login")) : '').'">';
  1333. print $langs->trans("GoToDolibarr");
  1334. print '</a></div>';
  1335. } else {
  1336. print '<div class="center warning" style="padding-top: 10px">';
  1337. print $langs->trans("SetAtLeastOneOptionAsUrlParameter");
  1338. print '</div>';
  1339. }
  1340. dolibarr_install_syslog("--- repair: end");
  1341. pFooter(1, $setuplang);
  1342. if ($db->connected) {
  1343. $db->close();
  1344. }
  1345. // Return code if ran from command line
  1346. if (!$ok && isset($argv[1])) {
  1347. exit(1);
  1348. }