dolibarr  18.0.6
repair.php
Go to the documentation of this file.
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 
28 include_once 'inc.php';
29 if (file_exists($conffile)) {
30  include_once $conffile;
31 }
32 require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php';
33 include_once $dolibarr_main_document_root.'/core/lib/images.lib.php';
34 require_once $dolibarr_main_document_root.'/core/class/extrafields.class.php';
35 require_once 'lib/repair.lib.php';
36 
37 $step = 2;
38 $ok = 0;
39 
40 
41 // Cette page peut etre longue. On augmente le delai autorise.
42 // Ne fonctionne que si on est pas en safe_mode.
43 $err = error_reporting();
44 error_reporting(0);
45 @set_time_limit(120);
46 error_reporting($err);
47 
48 $setuplang = GETPOST("selectlang", 'aZ09', 3) ?GETPOST("selectlang", 'aZ09', 3) : 'auto';
49 $langs->setDefaultLang($setuplang);
50 
51 $langs->loadLangs(array("admin", "install", "other"));
52 
53 if ($dolibarr_main_db_type == "mysqli") {
54  $choix = 1;
55 }
56 if ($dolibarr_main_db_type == "pgsql") {
57  $choix = 2;
58 }
59 if ($dolibarr_main_db_type == "mssql") {
60  $choix = 3;
61 }
62 
63 
64 dolibarr_install_syslog("--- repair: entering upgrade.php page");
65 if (!is_object($conf)) {
66  dolibarr_install_syslog("repair: conf file not initialized", LOG_ERR);
67 }
68 
69 
70 /*
71  * View
72  */
73 
74 pHeader('', "upgrade2", GETPOST('action', 'aZ09'));
75 
76 // Action to launch the repair script
77 $actiondone = 1;
78 
79 print '<h3>'.$langs->trans("Repair").'</h3>';
80 
81 print 'Option standard (\'test\' or \'confirmed\') is '.(GETPOST('standard', 'alpha') ?GETPOST('standard', 'alpha') : 'undefined').'<br>'."\n";
82 // Disable modules
83 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";
84 // Files
85 print 'Option restore_thirdparties_logos (\'test\' or \'confirmed\') is '.(GETPOST('restore_thirdparties_logos', 'alpha') ?GETPOST('restore_thirdparties_logos', 'alpha') : 'undefined').'<br>'."\n";
86 print 'Option restore_user_pictures (\'test\' or \'confirmed\') is '.(GETPOST('restore_user_pictures', 'alpha') ?GETPOST('restore_user_pictures', 'alpha') : 'undefined').'<br>'."\n";
87 print 'Option rebuild_product_thumbs (\'test\' or \'confirmed\') is '.(GETPOST('rebuild_product_thumbs', 'alpha') ?GETPOST('rebuild_product_thumbs', 'alpha') : 'undefined').'<br>'."\n";
88 // Clean tables and data
89 print 'Option clean_linked_elements (\'test\' or \'confirmed\') is '.(GETPOST('clean_linked_elements', 'alpha') ?GETPOST('clean_linked_elements', 'alpha') : 'undefined').'<br>'."\n";
90 print 'Option clean_menus (\'test\' or \'confirmed\') is '.(GETPOST('clean_menus', 'alpha') ?GETPOST('clean_menus', 'alpha') : 'undefined').'<br>'."\n";
91 print 'Option clean_orphelin_dir (\'test\' or \'confirmed\') is '.(GETPOST('clean_orphelin_dir', 'alpha') ?GETPOST('clean_orphelin_dir', 'alpha') : 'undefined').'<br>'."\n";
92 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";
93 print 'Option clean_perm_table (\'test\' or \'confirmed\') is '.(GETPOST('clean_perm_table', 'alpha') ?GETPOST('clean_perm_table', 'alpha') : 'undefined').'<br>'."\n";
94 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";
95 // Init data
96 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";
97 // Structure
98 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";
99 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";
100 // Rebuild sequence
101 print 'Option rebuild_sequences, for postgresql only (\'test\' or \'confirmed\') is '.(GETPOST('rebuild_sequences', 'alpha') ?GETPOST('rebuild_sequences', 'alpha') : 'undefined').'<br>'."\n";
102 print '<br>';
103 
104 print '<table cellspacing="0" cellpadding="1" border="0" width="100%">';
105 $error = 0;
106 
107 // If password is encoded, we decode it
108 if (preg_match('/crypted:/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
109  require_once $dolibarr_main_document_root.'/core/lib/security.lib.php';
110  if (preg_match('/crypted:/i', $dolibarr_main_db_pass)) {
111  $dolibarr_main_db_pass = preg_replace('/crypted:/i', '', $dolibarr_main_db_pass);
112  $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_pass);
113  $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
114  } else {
115  $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
116  }
117 }
118 
119 // $conf is already instancied inside inc.php
120 $conf->db->type = $dolibarr_main_db_type;
121 $conf->db->host = $dolibarr_main_db_host;
122 $conf->db->port = $dolibarr_main_db_port;
123 $conf->db->name = $dolibarr_main_db_name;
124 $conf->db->user = $dolibarr_main_db_user;
125 $conf->db->pass = $dolibarr_main_db_pass;
126 
127 // For encryption
128 $conf->db->dolibarr_main_db_encryption = isset($dolibarr_main_db_encryption) ? $dolibarr_main_db_encryption : '';
129 $conf->db->dolibarr_main_db_cryptkey = isset($dolibarr_main_db_cryptkey) ? $dolibarr_main_db_cryptkey : '';
130 
131 $db = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, (int) $conf->db->port);
132 
133 if ($db->connected) {
134  print '<tr><td class="nowrap">';
135  print $langs->trans("ServerConnection")." : $dolibarr_main_db_host</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
136  dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerConnection").": ".$dolibarr_main_db_host.$langs->transnoentities("OK"));
137  $ok = 1;
138 } else {
139  print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->transnoentities("Error")."</td></tr>";
140  dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
141  $ok = 0;
142 }
143 
144 if ($ok) {
145  if ($db->database_selected) {
146  print '<tr><td class="nowrap">';
147  print $langs->trans("DatabaseConnection")." : ".$dolibarr_main_db_name."</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
148  dolibarr_install_syslog("repair: database connection successful: ".$dolibarr_main_db_name);
149  $ok = 1;
150  } else {
151  print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->trans("Error")."</td></tr>";
152  dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
153  $ok = 0;
154  }
155 }
156 
157 // Show database version
158 if ($ok) {
159  $version = $db->getVersion();
160  $versionarray = $db->getVersionArray();
161  print '<tr><td>'.$langs->trans("ServerVersion").'</td>';
162  print '<td class="right">'.$version.'</td></tr>';
163  dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerVersion").": ".$version);
164  //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
165 }
166 
167 $conf->setValues($db);
168 // Reset forced setup after the setValues
169 if (defined('SYSLOG_FILE')) {
170  $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
171 }
172 $conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
173 
174 
175 /* Start action here */
176 $oneoptionset = 0;
177 $oneoptionset = (GETPOST('standard', 'alpha') || GETPOST('restore_thirdparties_logos', 'alpha') || GETPOST('clean_linked_elements', 'alpha') || GETPOST('clean_menus', 'alpha')
178  || GETPOST('clean_orphelin_dir', 'alpha') || GETPOST('clean_product_stock_batch', 'alpha') || GETPOST('set_empty_time_spent_amount', 'alpha') || GETPOST('rebuild_product_thumbs', 'alpha')
179  || GETPOST('clean_perm_table', 'alpha')
180  || GETPOST('force_disable_of_modules_not_found', 'alpha')
181  || GETPOST('force_utf8_on_tables', 'alpha') || GETPOST('force_utf8mb4_on_tables', 'alpha')
182  || GETPOST('rebuild_sequences', 'alpha'));
183 
184 if ($ok && $oneoptionset) {
185  // Show wait message
186  print '<tr><td colspan="2">'.$langs->trans("PleaseBePatient").'<br><br></td></tr>';
187  flush();
188 }
189 
190 
191 // run_sql: Run repair SQL file
192 if ($ok && GETPOST('standard', 'alpha')) {
193  $dir = "mysql/migration/";
194 
195  $filelist = array();
196  $i = 0;
197  $ok = 0;
198 
199  // Recupere list fichier
200  $filesindir = array();
201  $handle = opendir($dir);
202  if (is_resource($handle)) {
203  while (($file = readdir($handle)) !== false) {
204  if (preg_match('/\.sql$/i', $file)) {
205  $filesindir[] = $file;
206  }
207  }
208  }
209  sort($filesindir);
210 
211  foreach ($filesindir as $file) {
212  if (preg_match('/repair/i', $file)) {
213  $filelist[] = $file;
214  }
215  }
216 
217  // Loop on each file
218  foreach ($filelist as $file) {
219  print '<tr><td class="nowrap">*** ';
220  print $langs->trans("Script").'</td><td class="right">'.$file.'</td></tr>';
221 
222  $name = substr($file, 0, dol_strlen($file) - 4);
223 
224  // Run sql script
225  $ok = run_sql($dir.$file, 0, '', 1);
226  }
227 }
228 
229 
230 // sync_extrafields: Search list of fields declared and list of fields created into databases, then create fields missing
231 
232 if ($ok && GETPOST('standard', 'alpha')) {
233  $extrafields = new ExtraFields($db);
234 
235  // List of tables that has an extrafield table
236  $listofmodulesextra = array('societe'=>'societe', 'adherent'=>'adherent', 'product'=>'product',
237  'socpeople'=>'socpeople', 'propal'=>'propal', 'commande'=>'commande',
238  'facture'=>'facture', 'facturedet'=>'facturedet', 'facture_rec'=>'facture_rec', 'facturedet_rec'=>'facturedet_rec',
239  'supplier_proposal'=>'supplier_proposal', 'commande_fournisseur'=>'commande_fournisseur',
240  'facture_fourn'=>'facture_fourn', 'facture_fourn_rec'=>'facture_fourn_rec', 'facture_fourn_det'=>'facture_fourn_det', 'facture_fourn_det_rec'=>'facture_fourn_det_rec',
241  'fichinter'=>'fichinter', 'fichinterdet'=>'fichinterdet',
242  'inventory'=>'inventory',
243  'actioncomm'=>'actioncomm', 'bom_bom'=>'bom_bom', 'mrp_mo'=>'mrp_mo',
244  'adherent_type'=>'adherent_type', 'user'=>'user', 'partnership'=>'partnership', 'projet'=>'projet', 'projet_task'=>'projet_task', 'ticket'=>'ticket');
245  //$listofmodulesextra = array('fichinter'=>'fichinter');
246 
247  print '<tr><td colspan="2"><br>*** Check fields into extra table structure match table of definition. If not add column into table</td></tr>';
248  foreach ($listofmodulesextra as $tablename => $elementtype) {
249  // Get list of fields
250  $tableextra = MAIN_DB_PREFIX.$tablename.'_extrafields';
251 
252  // Define $arrayoffieldsdesc
253  $arrayoffieldsdesc = $extrafields->fetch_name_optionals_label($elementtype);
254 
255  // Define $arrayoffieldsfound
256  $arrayoffieldsfound = array();
257  $resql = $db->DDLDescTable($tableextra);
258  if ($resql) {
259  print '<tr><td>Check availability of extra field for '.$tableextra;
260  $i = 0;
261  while ($obj = $db->fetch_object($resql)) {
262  $fieldname = $fieldtype = '';
263  if (preg_match('/mysql/', $db->type)) {
264  $fieldname = $obj->Field;
265  $fieldtype = $obj->Type;
266  } else {
267  $fieldname = isset($obj->Key) ? $obj->Key : $obj->attname;
268  $fieldtype = isset($obj->Type) ? $obj->Type : 'varchar';
269  }
270 
271  if (empty($fieldname)) {
272  continue;
273  }
274  if (in_array($fieldname, array('rowid', 'tms', 'fk_object', 'import_key'))) {
275  continue;
276  }
277  $arrayoffieldsfound[$fieldname] = array('type'=>$fieldtype);
278  }
279  print ' - Found '.count($arrayoffieldsfound).' fields into table';
280  if (count($arrayoffieldsfound) > 0) {
281  print ' <span class="opacitymedium">('.join(', ', array_keys($arrayoffieldsfound)).')</span>';
282  }
283  print '<br>'."\n";
284 
285  // If it does not match, we create fields
286  foreach ($arrayoffieldsdesc as $code => $label) {
287  if (!in_array($code, array_keys($arrayoffieldsfound))) {
288  print 'Found field '.$code.' declared into '.MAIN_DB_PREFIX.'extrafields table but not found into desc of table '.$tableextra." -> ";
289  $type = $extrafields->attributes[$elementtype]['type'][$code]; $length = $extrafields->attributes[$elementtype]['size'][$code]; $attribute = ''; $default = ''; $extra = ''; $null = 'null';
290 
291  if ($type == 'boolean') {
292  $typedb = 'int';
293  $lengthdb = '1';
294  } elseif ($type == 'price') {
295  $typedb = 'double';
296  $lengthdb = '24,8';
297  } elseif ($type == 'phone') {
298  $typedb = 'varchar';
299  $lengthdb = '20';
300  } elseif ($type == 'mail') {
301  $typedb = 'varchar';
302  $lengthdb = '128';
303  } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
304  $typedb = 'text';
305  $lengthdb = '';
306  } elseif ($type == 'link') {
307  $typedb = 'int';
308  $lengthdb = '11';
309  } else {
310  $typedb = $type;
311  $lengthdb = $length;
312  }
313 
314  $field_desc = array(
315  'type'=>$typedb,
316  'value'=>$lengthdb,
317  'attribute'=>$attribute,
318  'default'=>$default,
319  'extra'=>$extra,
320  'null'=>$null
321  );
322  //var_dump($field_desc);exit;
323 
324  $result = 0;
325  if (GETPOST('standard', 'alpha') == 'confirmed') {
326  $result = $db->DDLAddField($tableextra, $code, $field_desc, "");
327 
328  if ($result < 0) {
329  print "KO ".$db->lasterror."<br>\n";
330  } else {
331  print "OK<br>\n";
332  }
333  } else {
334  print ' - Mode test, no column added.';
335  }
336  }
337  }
338 
339  print "</td><td>&nbsp;</td></tr>\n";
340  } else {
341  print '<tr><td>Table '.$tableextra.' is not found</td><td></td></tr>'."\n";
342  }
343  }
344 }
345 
346 
347 // clean_data_ecm_dir: Clean data into ecm_directories table
348 if ($ok && GETPOST('standard', 'alpha')) {
350 }
351 
352 
353 // clean declaration constants
354 if ($ok && GETPOST('standard', 'alpha')) {
355  print '<tr><td colspan="2"><br>*** Clean constant record of modules not enabled</td></tr>';
356 
357  $sql = "SELECT name, entity, value";
358  $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
359  $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'";
360  $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'";
361  $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_%'";
362  $sql .= " OR name LIKE 'MAIN_MODULE_%_MODULEFOREXTERNAL'";
363  $sql .= " ORDER BY name, entity";
364 
365  $resql = $db->query($sql);
366  if ($resql) {
367  $num = $db->num_rows($resql);
368 
369  if ($num) {
370  $db->begin();
371 
372  $i = 0;
373  while ($i < $num) {
374  $obj = $db->fetch_object($resql);
375 
376  $reg = array();
377  if (preg_match('/MAIN_MODULE_([^_]+)_(.+)/i', $obj->name, $reg)) {
378  $name = $reg[1];
379  $type = $reg[2];
380 
381  $sql2 = "SELECT COUNT(*) as nb";
382  $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
383  $sql2 .= " WHERE name = 'MAIN_MODULE_".$name."'";
384  $sql2 .= " AND entity = ".((int) $obj->entity);
385  $resql2 = $db->query($sql2);
386  if ($resql2) {
387  $obj2 = $db->fetch_object($resql2);
388  if ($obj2 && $obj2->nb == 0) {
389  // Module not found, so we can remove entry
390  $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = '".$db->escape($obj->name)."' AND entity = ".((int) $obj->entity);
391 
392  if (GETPOST('standard', 'alpha') == 'confirmed') {
393  $db->query($sqldelete);
394 
395  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>';
396  } else {
397  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>';
398  }
399  } else {
400  //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>';
401  }
402  }
403  }
404 
405  $i++;
406  }
407 
408  $db->commit();
409  }
410  } else {
411  dol_print_error($db);
412  }
413 }
414 
415 
416 // clean box of not enabled modules
417 if ($ok && GETPOST('standard', 'alpha')) {
418  print '<tr><td colspan="2"><br>*** Clean definition of boxes of modules not enabled</td></tr>';
419 
420  $sql = "SELECT file, entity FROM ".MAIN_DB_PREFIX."boxes_def";
421  $sql .= " WHERE file like '%@%'";
422 
423  $resql = $db->query($sql);
424  if ($resql) {
425  $num = $db->num_rows($resql);
426 
427  if ($num) {
428  $db->begin();
429 
430  $i = 0;
431  while ($i < $num) {
432  $obj = $db->fetch_object($resql);
433 
434  $reg = array();
435  if (preg_match('/^(.+)@(.+)$/i', $obj->file, $reg)) {
436  $name = $reg[1];
437  $module = $reg[2];
438 
439  $sql2 = "SELECT COUNT(*) as nb";
440  $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
441  $sql2 .= " WHERE name = 'MAIN_MODULE_".strtoupper($module)."'";
442  $sql2 .= " AND entity = ".((int) $obj->entity);
443  $sql2 .= " AND value <> 0";
444  $resql2 = $db->query($sql2);
445  if ($resql2) {
446  $obj2 = $db->fetch_object($resql2);
447  if ($obj2 && $obj2->nb == 0) {
448  // Module not found, so we canremove entry
449  $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).")";
450  $sqldeleteb = "DELETE FROM ".MAIN_DB_PREFIX."boxes_def WHERE file = '".$db->escape($obj->file)."' AND entity = ".((int) $obj->entity);
451 
452  if (GETPOST('standard', 'alpha') == 'confirmed') {
453  $db->query($sqldeletea);
454  $db->query($sqldeleteb);
455 
456  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>';
457  } else {
458  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>';
459  }
460  } else {
461  //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>';
462  }
463  }
464  }
465 
466  $i++;
467  }
468 
469  $db->commit();
470  }
471  }
472 }
473 
474 
475 // restore_thirdparties_logos: Move logos to correct new directory.
476 if ($ok && GETPOST('restore_thirdparties_logos')) {
477  //$exts=array('gif','png','jpg');
478 
479  $ext = '';
480 
481  print '<tr><td colspan="2"><br>*** Restore thirdparties logo<br>';
482 
483  $sql = "SELECT s.rowid, s.nom as name, s.logo FROM ".MAIN_DB_PREFIX."societe as s ORDER BY s.nom";
484  $resql = $db->query($sql);
485  if ($resql) {
486  $num = $db->num_rows($resql);
487  $i = 0;
488 
489  while ($i < $num) {
490  $obj = $db->fetch_object($resql);
491 
492  /*
493  $name=preg_replace('/é/','',$obj->name);
494  $name=preg_replace('/ /','_',$name);
495  $name=preg_replace('/\'/','',$name);
496  */
497 
498  $tmp = explode('.', $obj->logo);
499  $name = $tmp[0];
500  if (isset($tmp[1])) {
501  $ext = '.'.$tmp[1];
502  }
503 
504  if (!empty($name)) {
505  $filetotest = $dolibarr_main_data_root.'/societe/logos/'.$name.$ext;
506  $filetotestsmall = $dolibarr_main_data_root.'/societe/logos/thumbs/'.$name.'_small'.$ext;
507  $exists = dol_is_file($filetotest);
508  print 'Check thirdparty '.$obj->rowid.' name='.$obj->name.' logo='.$obj->logo.' file '.$filetotest." exists=".$exists."<br>\n";
509  if ($exists) {
510  $filetarget = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/'.$name.$ext;
511  $filetargetsmall = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs/'.$name.'_small'.$ext;
512  $existt = dol_is_file($filetarget);
513  if (!$existt) {
514  if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
515  dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos');
516  }
517 
518  print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
519  if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
520  dol_copy($filetotest, $filetarget, '', 0);
521  }
522  }
523 
524  $existtt = dol_is_file($filetargetsmall);
525  if (!$existtt) {
526  if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
527  dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs');
528  }
529  print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
530  if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
531  dol_copy($filetotestsmall, $filetargetsmall, '', 0);
532  }
533  }
534  }
535  }
536 
537  $i++;
538  }
539  } else {
540  $ok = 0;
541  dol_print_error($db);
542  }
543 
544  print '</td></tr>';
545 }
546 
547 
548 
549 // restore_user_pictures: Move pictures to correct new directory.
550 if ($ok && GETPOST('restore_user_pictures', 'alpha')) {
551  //$exts=array('gif','png','jpg');
552 
553  $ext = '';
554 
555  print '<tr><td colspan="2"><br>*** Restore user pictures<br>';
556 
557  $sql = "SELECT s.rowid, s.firstname, s.lastname, s.login, s.photo FROM ".MAIN_DB_PREFIX."user as s ORDER BY s.rowid";
558  $resql = $db->query($sql);
559  if ($resql) {
560  $num = $db->num_rows($resql);
561  $i = 0;
562 
563  while ($i < $num) {
564  $obj = $db->fetch_object($resql);
565 
566  /*
567  $name=preg_replace('/é/','',$obj->name);
568  $name=preg_replace('/ /','_',$name);
569  $name=preg_replace('/\'/','',$name);
570  */
571 
572  $tmp = explode('.', $obj->photo);
573  $name = $tmp[0];
574  if (isset($tmp[1])) {
575  $ext = '.'.$tmp[1];
576  }
577 
578  if (!empty($name)) {
579  $filetotest = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/'.$name.$ext;
580  $filetotestsmall = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_small'.$ext;
581  $filetotestmini = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_mini'.$ext;
582  $exists = dol_is_file($filetotest);
583  print 'Check user '.$obj->rowid.' lastname='.$obj->lastname.' firstname='.$obj->firstname.' photo='.$obj->photo.' file '.$filetotest." exists=".$exists."<br>\n";
584  if ($exists) {
585  $filetarget = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/'.$name.$ext;
586  $filetargetsmall = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_small'.$ext;
587  $filetargetmini = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_mini'.$ext;
588 
589  $existt = dol_is_file($filetarget);
590  if (!$existt) {
591  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
592  dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid);
593  }
594 
595  print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
596  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
597  dol_copy($filetotest, $filetarget, '', 0);
598  }
599  }
600 
601  $existtt = dol_is_file($filetargetsmall);
602  if (!$existtt) {
603  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
604  dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
605  }
606 
607  print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
608  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
609  dol_copy($filetotestsmall, $filetargetsmall, '', 0);
610  }
611  }
612 
613  $existtt = dol_is_file($filetargetmini);
614  if (!$existtt) {
615  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
616  dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
617  }
618 
619  print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestmini." -> ".$filetargetmini."<br>\n";
620  if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
621  dol_copy($filetotestmini, $filetargetmini, '', 0);
622  }
623  }
624  }
625  }
626 
627  $i++;
628  }
629  } else {
630  $ok = 0;
631  dol_print_error($db);
632  }
633 
634  print '</td></tr>';
635 }
636 
637 
638 // rebuild_product_thumbs: Rebuild thumbs for product files
639 if ($ok && GETPOST('rebuild_product_thumbs', 'alpha')) {
640  $ext = '';
641  global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
642 
643  print '<tr><td colspan="2"><br>*** Rebuild product thumbs<br>';
644 
645  $sql = "SELECT s.rowid, s.ref FROM ".MAIN_DB_PREFIX."product as s ORDER BY s.ref";
646  $resql = $db->query($sql);
647  if ($resql) {
648  $num = $db->num_rows($resql);
649  $i = 0;
650 
651  while ($i < $num) {
652  $obj = $db->fetch_object($resql);
653 
654  if (!empty($obj->ref)) {
655  $files = dol_dir_list($dolibarr_main_data_root.'/produit/'.$obj->ref, 'files', 0);
656  foreach ($files as $file) {
657  // Generate thumbs.
658  if (image_format_supported($file['fullname']) == 1) {
659  $imgThumbSmall = 'notbuild';
660  if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
661  // Used on logon for example
662  $imgThumbSmall = vignette($file['fullname'], $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
663  }
664  print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbSmall." maxwidthsmall=".$maxwidthsmall." maxheightsmall=".$maxheightsmall."<br>\n";
665  $imgThumbMini = 'notbuild';
666  if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
667  // Create mini thumbs for image (Ratio is near 16/9)
668  // Used on menu or for setup page for example
669  $imgThumbMini = vignette($file['fullname'], $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
670  }
671  print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbMini." maxwidthmini=".$maxwidthmini." maxheightmini=".$maxheightmini."<br>\n";
672  }
673  }
674  }
675 
676  $i++;
677  }
678  } else {
679  $ok = 0;
680  dol_print_error($db);
681  }
682 
683  print '</td></tr>';
684 }
685 
686 // clean_linked_elements: Check and clean linked elements
687 if ($ok && GETPOST('clean_linked_elements', 'alpha')) {
688  print '<tr><td colspan="2"><br>*** Check table of linked elements and delete orphelins links</td></tr>';
689  // propal => order
690  print '<tr><td colspan="2">'.checkLinkedElements('propal', 'commande')."</td></tr>\n";
691 
692  // propal => invoice
693  print '<tr><td colspan="2">'.checkLinkedElements('propal', 'facture')."</td></tr>\n";
694 
695  // order => invoice
696  print '<tr><td colspan="2">'.checkLinkedElements('commande', 'facture')."</td></tr>\n";
697 
698  // order => shipping
699  print '<tr><td colspan="2">'.checkLinkedElements('commande', 'shipping')."</td></tr>\n";
700 
701  // shipping => delivery
702  print '<tr><td colspan="2">'.checkLinkedElements('shipping', 'delivery')."</td></tr>\n";
703 
704  // order_supplier => invoice_supplier
705  print '<tr><td colspan="2">'.checkLinkedElements('order_supplier', 'invoice_supplier')."</td></tr>\n";
706 }
707 
708 
709 // clean_menus: Check orphelins menus
710 if ($ok && GETPOST('clean_menus', 'alpha')) {
711  print '<tr><td colspan="2"><br>*** Clean menu entries coming from disabled modules</td></tr>';
712 
713  $sql = "SELECT rowid, module";
714  $sql .= " FROM ".MAIN_DB_PREFIX."menu as c";
715  $sql .= " WHERE module IS NOT NULL AND module <> ''";
716  $sql .= " ORDER BY module";
717 
718  $resql = $db->query($sql);
719  if ($resql) {
720  $num = $db->num_rows($resql);
721  if ($num) {
722  $i = 0;
723  while ($i < $num) {
724  $obj = $db->fetch_object($resql);
725 
726  $modulecond = $obj->module;
727  $modulecondarray = explode('|', $obj->module); // Name of module
728 
729  print '<tr><td>';
730  print $modulecond;
731 
732  $db->begin();
733 
734  if ($modulecond) { // And menu entry for module $modulecond was found in database.
735  $moduleok = 0;
736  foreach ($modulecondarray as $tmpname) {
737  if ($tmpname == 'margins') {
738  $tmpname = 'margin'; // TODO Remove this when normalized
739  }
740 
741  $result = 0;
742  if (!empty($conf->$tmpname)) {
743  $result = $conf->$tmpname->enabled;
744  }
745  if ($result) {
746  $moduleok++;
747  }
748  }
749 
750  if (!$moduleok && $modulecond) {
751  print ' - Module condition '.$modulecond.' seems ko, we delete menu entry.';
752  if (GETPOST('clean_menus') == 'confirmed') {
753  $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."menu WHERE module = '".$db->escape($modulecond)."'";
754  $resql2 = $db->query($sql2);
755  if (!$resql2) {
756  $error++;
757  dol_print_error($db);
758  } else {
759  print ' - <span class="warning">Cleaned</span>';
760  }
761  } else {
762  print ' - <span class="warning">Canceled (test mode)</span>';
763  }
764  } else {
765  print ' - Module condition '.$modulecond.' is ok, we do nothing.';
766  }
767  }
768 
769  if (!$error) {
770  $db->commit();
771  } else {
772  $db->rollback();
773  }
774 
775  print'</td></tr>';
776 
777  if ($error) {
778  break;
779  }
780 
781  $i++;
782  }
783  } else {
784  print '<tr><td>No menu entries of disabled menus found</td></tr>';
785  }
786  } else {
787  dol_print_error($db);
788  }
789 }
790 
791 
792 
793 // clean_orphelin_dir: Run purge of directory
794 if ($ok && GETPOST('clean_orphelin_dir', 'alpha')) {
795  $listmodulepart = array('company', 'invoice', 'invoice_supplier', 'propal', 'order', 'order_supplier', 'contract', 'tax');
796  foreach ($listmodulepart as $modulepart) {
797  $filearray = array();
798  $upload_dir = isset($conf->$modulepart->dir_output) ? $conf->$modulepart->dir_output : '';
799  if ($modulepart == 'company') {
800  $upload_dir = $conf->societe->dir_output; // TODO change for multicompany sharing
801  }
802  if ($modulepart == 'invoice') {
803  $upload_dir = $conf->facture->dir_output;
804  }
805  if ($modulepart == 'invoice_supplier') {
806  $upload_dir = $conf->fournisseur->facture->dir_output;
807  }
808  if ($modulepart == 'order') {
809  $upload_dir = $conf->commande->dir_output;
810  }
811  if ($modulepart == 'order_supplier') {
812  $upload_dir = $conf->fournisseur->commande->dir_output;
813  }
814  if ($modulepart == 'contract') {
815  $upload_dir = $conf->contrat->dir_output;
816  }
817 
818  if (empty($upload_dir)) {
819  continue;
820  }
821 
822  print '<tr><td colspan="2"><br>*** Clean orphelins files into files '.$upload_dir.'</td></tr>';
823 
824  $filearray = dol_dir_list($upload_dir, "files", 1, '', array('^SPECIMEN\.pdf$', '^\.', '(\.meta|_preview.*\.png)$', '^temp$', '^payments$', '^CVS$', '^thumbs$'), '', SORT_DESC, 1, true);
825 
826  // To show ref or specific information according to view to show (defined by $module)
827  if ($modulepart == 'company') {
828  include_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
829  $object_instance = new Societe($db);
830  }
831  if ($modulepart == 'invoice') {
832  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
833  $object_instance = new Facture($db);
834  } elseif ($modulepart == 'invoice_supplier') {
835  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
836  $object_instance = new FactureFournisseur($db);
837  } elseif ($modulepart == 'propal') {
838  include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
839  $object_instance = new Propal($db);
840  } elseif ($modulepart == 'order') {
841  include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
842  $object_instance = new Commande($db);
843  } elseif ($modulepart == 'order_supplier') {
844  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
845  $object_instance = new CommandeFournisseur($db);
846  } elseif ($modulepart == 'contract') {
847  include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
848  $object_instance = new Contrat($db);
849  } elseif ($modulepart == 'tax') {
850  include_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php';
851  $object_instance = new ChargeSociales($db);
852  }
853 
854  foreach ($filearray as $key => $file) {
855  if (!is_dir($file['name'])
856  && $file['name'] != '.'
857  && $file['name'] != '..'
858  && $file['name'] != 'CVS'
859  ) {
860  // Define relative path used to store the file
861  $relativefile = preg_replace('/'.preg_quote($upload_dir.'/', '/').'/', '', $file['fullname']);
862 
863  //var_dump($file);
864  $id = 0; $ref = ''; $object_instance->id = 0; $object_instance->ref = ''; $label = '';
865 
866  // To show ref or specific information according to view to show (defined by $module)
867  if ($modulepart == 'invoice') {
868  preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
869  }
870  if ($modulepart == 'invoice_supplier') {
871  preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg); $id = empty($reg[1]) ? '' : $reg[1];
872  }
873  if ($modulepart == 'propal') {
874  preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
875  }
876  if ($modulepart == 'order') {
877  preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
878  }
879  if ($modulepart == 'order_supplier') {
880  preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
881  }
882  if ($modulepart == 'contract') {
883  preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg); $ref = $reg[1];
884  }
885  if ($modulepart == 'tax') {
886  preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg); $id = $reg[1];
887  }
888 
889  if ($id || $ref) {
890  //print 'Fetch '.$id.' or '.$ref.'<br>';
891  $result = $object_instance->fetch($id, $ref);
892  //print $result.'<br>';
893  if ($result == 0) { // Not found but no error
894  // Clean of orphelins directories are done into repair.php
895  print '<tr><td colspan="2">';
896  print 'Delete orphelins file '.$file['fullname'].'<br>';
897  if (GETPOST('clean_orphelin_dir', 'alpha') == 'confirmed') {
898  dol_delete_file($file['fullname'], 1, 1, 1);
899  dol_delete_dir(dirname($file['fullname']), 1);
900  }
901  print "</td></tr>";
902  } elseif ($result < 0) {
903  print 'Error in '.get_class($object_instance).'.fetch of id'.$id.' ref='.$ref.', result='.$result.'<br>';
904  }
905  }
906  }
907  }
908  }
909 }
910 
911 // clean_linked_elements: Check and clean linked elements
912 if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) {
913  $methodtofix = GETPOST('methodtofix', 'alpha') ?GETPOST('methodtofix', 'alpha') : 'updatestock';
914 
915  print '<tr><td colspan="2"><br>*** Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
916 
917  $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
918  $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";
919  $sql .= " WHERE p.rowid = ps.fk_product";
920  $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
921  $sql .= " HAVING (SUM(pb.qty) IS NOT NULL AND reel != SUM(pb.qty)) OR (SUM(pb.qty) IS NULL AND p.tobatch > 0)";
922  print $sql;
923  $resql = $db->query($sql);
924  if ($resql) {
925  $num = $db->num_rows($resql);
926 
927  if ($num) {
928  $i = 0;
929  while ($i < $num) {
930  $obj = $db->fetch_object($resql);
931  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)';
932 
933  // Fix is required
934  if ($obj->reel != $obj->reelbatch) {
935  if (empty($obj->tobatch)) {
936  // If product is not a product that support batches, we can clean stock by deleting the product batch lines
937  print ' -> Delete qty '.$obj->reelbatch.' for any lot linked to fk_product_stock='.$obj->psrowid;
938  $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."product_batch";
939  $sql2 .= " WHERE fk_product_stock = ".((int) $obj->psrowid);
940  print '<br>'.$sql2;
941 
942  if (GETPOST('clean_product_stock_batch') == 'confirmed') {
943  $resql2 = $db->query($sql2);
944  if (!$resql2) {
945  $error++;
946  dol_print_error($db);
947  }
948  }
949  } else {
950  if ($methodtofix == 'updatebatch') {
951  // Method 1
952  print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid;
953  $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)";
954  $sql2 .= "VALUES(".((int) $obj->psrowid).", '000000', ".((float) ($obj->reel - $obj->reelbatch)).")";
955  print '<br>'.$sql2;
956 
957  if (GETPOST('clean_product_stock_batch') == 'confirmed') {
958  $resql2 = $db->query($sql2);
959  if (!$resql2) {
960  // TODO If it fails, we must make update
961  //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch";
962  //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")";
963  //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid)
964  }
965  }
966  }
967  if ($methodtofix == 'updatestock') {
968  // Method 2
969  print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid);
970  $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock";
971  $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid);
972  print '<br>'.$sql2;
973 
974  if (GETPOST('clean_product_stock_batch') == 'confirmed') {
975  $error = 0;
976 
977  $db->begin();
978 
979  $resql2 = $db->query($sql2);
980  if ($resql2) {
981  // We update product_stock, so we must fill p.stock into product too.
982  $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)';
983  $resql3 = $db->query($sql3);
984  if (!$resql3) {
985  $error++;
986  dol_print_error($db);
987  }
988  } else {
989  $error++;
990  dol_print_error($db);
991  }
992 
993  if (!$error) {
994  $db->commit();
995  } else {
996  $db->rollback();
997  }
998  }
999  }
1000  }
1001  }
1002 
1003  print'</td></tr>';
1004 
1005  $i++;
1006  }
1007  } else {
1008  print '<tr><td colspan="2">Nothing to do</td></tr>';
1009  }
1010  } else {
1011  dol_print_error($db);
1012  }
1013 }
1014 
1015 
1016 // clean_product_stock_negative_if_batch
1017 if ($ok && GETPOST('clean_product_stock_negative_if_batch', 'alpha')) {
1018  print '<tr><td colspan="2"><br>Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
1019 
1020  $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
1021  $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product_batch as pb";
1022  $sql .= " WHERE p.rowid = ps.fk_product AND ps.rowid = pb.fk_product_stock";
1023  $sql .= " AND p.tobatch > 0";
1024  $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
1025  $sql .= " HAVING reel != SUM(pb.qty)";
1026  $resql = $db->query($sql);
1027  if ($resql) {
1028  $num = $db->num_rows($resql);
1029 
1030  if ($num) {
1031  $i = 0;
1032  while ($i < $num) {
1033  $obj = $db->fetch_object($resql);
1034  print '<tr><td>'.$obj->rowid.'-'.$obj->ref.'-'.$obj->fk_entrepot.' -> '.$obj->psrowid.': '.$obj->reel.' != '.$obj->reelbatch;
1035 
1036  // TODO
1037  }
1038  }
1039  }
1040 }
1041 
1042 // set_empty_time_spent_amount
1043 if ($ok && GETPOST('set_empty_time_spent_amount', 'alpha')) {
1044  print '<tr><td colspan="2"><br>*** Set value of time spent without amount</td></tr>';
1045 
1046  $sql = "SELECT COUNT(ptt.rowid) as nb, u.rowid as user_id, u.login, u.thm as user_thm";
1047  $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."user as u";
1048  $sql .= " WHERE ptt.fk_user = u.rowid";
1049  $sql .= " AND ptt.thm IS NULL and u.thm > 0";
1050  $sql .= " GROUP BY u.rowid, u.login, u.thm";
1051 
1052  $resql = $db->query($sql);
1053  if ($resql) {
1054  $num = $db->num_rows($resql);
1055 
1056  if ($num) {
1057  $i = 0;
1058  while ($i < $num) {
1059  $obj = $db->fetch_object($resql);
1060  print '<tr><td>'.$obj->login.'-'.$obj->user_id.' ('.$obj->nb.' lines to fix) -> '.$obj->user_thm;
1061 
1062  $db->begin();
1063 
1064  if (GETPOST('set_empty_time_spent_amount') == 'confirmed') {
1065  $sql2 = "UPDATE ".MAIN_DB_PREFIX."element_time";
1066  $sql2 .= " SET thm = ".$obj->user_thm." WHERE thm IS NULL AND fk_user = ".((int) $obj->user_id);
1067  $resql2 = $db->query($sql2);
1068  if (!$resql2) {
1069  $error++;
1070  dol_print_error($db);
1071  }
1072  }
1073 
1074  if (!$error) {
1075  $db->commit();
1076  } else {
1077  $db->rollback();
1078  }
1079 
1080  print'</td></tr>';
1081 
1082  if ($error) {
1083  break;
1084  }
1085 
1086  $i++;
1087  }
1088  } else {
1089  print '<tr><td>No time spent with empty line on users with a hourly rate defined</td></tr>';
1090  }
1091  } else {
1092  dol_print_error($db);
1093  }
1094 }
1095 
1096 
1097 // force_disable_of_modules_not_found
1098 if ($ok && GETPOST('force_disable_of_modules_not_found', 'alpha')) {
1099  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>';
1100 
1101  $arraylistofkey = array('hooks', 'js', 'css');
1102 
1103  foreach ($arraylistofkey as $key) {
1104  $sql = "SELECT DISTINCT name, value";
1105  $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
1106  $sql .= " WHERE name LIKE 'MAIN_MODULE_%_".strtoupper($key)."'";
1107  $sql .= " ORDER BY name";
1108 
1109  $resql = $db->query($sql);
1110  if ($resql) {
1111  $num = $db->num_rows($resql);
1112  if ($num) {
1113  $i = 0;
1114  while ($i < $num) {
1115  $obj = $db->fetch_object($resql);
1116  $constantname = $obj->name; // Name of constant for hook or js or css declaration
1117 
1118  print '<tr><td>';
1119  print dol_escape_htmltag($constantname);
1120 
1121  $db->begin();
1122 
1123  $reg = array();
1124  if (preg_match('/MAIN_MODULE_(.*)_'.strtoupper($key).'/i', $constantname, $reg)) {
1125  $name = strtolower($reg[1]);
1126 
1127  if ($name) { // An entry for key $key and module $name was found in database.
1128  $reloffile = '';
1129  $result = 'found';
1130 
1131  if ($key == 'hooks') {
1132  $reloffile = $name.'/class/actions_'.$name.'.class.php';
1133  }
1134  if ($key == 'js') {
1135  $value = $obj->value;
1136  $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1137  $reloffile = $valuearray[0];
1138  $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1139  }
1140  if ($key == 'css') {
1141  $value = $obj->value;
1142  $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1143  if ($value && (!is_array($valuearray) || count($valuearray) == 0)) {
1144  $valuearray = array();
1145  $valuearray[0] = $value; // If value was not a json array but a string
1146  }
1147  $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1148  }
1149 
1150  if ($reloffile) {
1151  //var_dump($key.' - '.$value.' - '.$reloffile);
1152  try {
1153  $result = dol_buildpath($reloffile, 0, 2);
1154  } catch (Exception $e) {
1155  $result = 'found'; // If error, we force like if we found to avoid any deletion
1156  }
1157  } else {
1158  $result = 'found'; //
1159  }
1160 
1161  if (!$result) {
1162  print ' - File of '.$key.' ('.$reloffile.') NOT found, we disable the module.';
1163  if (GETPOST('force_disable_of_modules_not_found') == 'confirmed') {
1164  $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."_".strtoupper($key)."'";
1165  $resql2 = $db->query($sql2);
1166  if (!$resql2) {
1167  $error++;
1168  dol_print_error($db);
1169  }
1170  $sql3 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."'";
1171  $resql3 = $db->query($sql3);
1172  if (!$resql3) {
1173  $error++;
1174  dol_print_error($db);
1175  } else {
1176  print ' - <span class="warning">Cleaned</span>';
1177  }
1178  } else {
1179  print ' - <span class="warning">Canceled (test mode)</span>';
1180  }
1181  } else {
1182  print ' - File of '.$key.' ('.$reloffile.') found, we do nothing.';
1183  }
1184  }
1185 
1186  if (!$error) {
1187  $db->commit();
1188  } else {
1189  $db->rollback();
1190  }
1191  }
1192 
1193  print'</td></tr>';
1194 
1195  if ($error) {
1196  break;
1197  }
1198 
1199  $i++;
1200  }
1201  } else {
1202  print '<tr><td>No active module with missing files found by searching on MAIN_MODULE_(.*)_'.strtoupper($key).'</td></tr>';
1203  }
1204  } else {
1205  dol_print_error($db);
1206  }
1207  }
1208 }
1209 
1210 
1211 // clean_old_module_entries: Clean data into const when files of module were removed without being
1212 if ($ok && GETPOST('clean_perm_table', 'alpha')) {
1213  print '<tr><td colspan="2"><br>*** Clean table user_rights from lines of external modules no more enabled</td></tr>';
1214 
1215  $listofmods = '';
1216  foreach ($conf->modules as $key => $val) {
1217  $listofmods .= ($listofmods ? ',' : '')."'".$db->escape($val)."'";
1218  }
1219 
1220  $sql = "SELECT id, libelle as label, module from ".MAIN_DB_PREFIX."rights_def WHERE module NOT IN (".$db->sanitize($listofmods, 1).") AND id > 100000";
1221 
1222  $resql = $db->query($sql);
1223  if ($resql) {
1224  $num = $db->num_rows($resql);
1225  if ($num) {
1226  $i = 0;
1227  while ($i < $num) {
1228  $obj = $db->fetch_object($resql);
1229  if ($obj->id > 0) {
1230  print '<tr><td>Found line with id '.$obj->id.', label "'.$obj->label.'" of module "'.$obj->module.'" to delete';
1231  if (GETPOST('clean_perm_table', 'alpha') == 'confirmed') {
1232  $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."rights_def WHERE id = ".((int) $obj->id);
1233  $resqldelete = $db->query($sqldelete);
1234  if (!$resqldelete) {
1235  dol_print_error($db);
1236  }
1237  print ' - deleted';
1238  }
1239  print '</td></tr>';
1240  }
1241  $i++;
1242  }
1243  } else {
1244  print '<tr><td>No lines of a disabled external module (with id > 100000) found into table rights_def</td></tr>';
1245  }
1246  } else {
1247  dol_print_error($db);
1248  }
1249 }
1250 
1251 
1252 
1253 // force utf8 on tables
1254 if ($ok && GETPOST('force_utf8_on_tables', 'alpha')) {
1255  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>';
1256 
1257  if ($db->type == "mysql" || $db->type == "mysqli") {
1258  $force_utf8_on_tables = GETPOST('force_utf8_on_tables', 'alpha');
1259 
1260  $listoftables = $db->DDLListTablesFull($db->database_name);
1261 
1262  // Disable foreign key checking for avoid errors
1263  if ($force_utf8_on_tables == 'confirmed') {
1264  $sql = 'SET FOREIGN_KEY_CHECKS=0';
1265  print '<!-- '.$sql.' -->';
1266  $resql = $db->query($sql);
1267  }
1268 
1269  foreach ($listoftables as $table) {
1270  // do not convert llx_const if mysql encrypt/decrypt is used
1271  if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1272  continue;
1273  }
1274  if ($table[1] == 'VIEW') {
1275  print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1276  continue;
1277  }
1278 
1279  print '<tr><td colspan="2">';
1280  print $table[0];
1281  $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1282  $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci";
1283  print '<!-- '.$sql1.' -->';
1284  print '<!-- '.$sql2.' -->';
1285  if ($force_utf8_on_tables == 'confirmed') {
1286  $resql1 = $db->query($sql1);
1287  if ($resql1) {
1288  $resql2 = $db->query($sql2);
1289  } else {
1290  $resql2 = false;
1291  }
1292  print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
1293  } else {
1294  print ' - Disabled';
1295  }
1296  print '</td></tr>';
1297  }
1298 
1299  // Enable foreign key checking
1300  if ($force_utf8_on_tables == 'confirmed') {
1301  $sql = 'SET FOREIGN_KEY_CHECKS=1';
1302  print '<!-- '.$sql.' -->';
1303  $resql = $db->query($sql);
1304  }
1305  } else {
1306  print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1307  }
1308 }
1309 
1310 // force utf8mb4 on tables EXPERIMENTAL !
1311 if ($ok && GETPOST('force_utf8mb4_on_tables', 'alpha')) {
1312  print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8mb4/utf8mb4_unicode_ci (for mysql/mariadb only)</td></tr>';
1313 
1314  if ($db->type == "mysql" || $db->type == "mysqli") {
1315  $force_utf8mb4_on_tables = GETPOST('force_utf8mb4_on_tables', 'alpha');
1316 
1317  $listoftables = $db->DDLListTablesFull($db->database_name);
1318 
1319  // Disable foreign key checking for avoid errors
1320  if ($force_utf8mb4_on_tables == 'confirmed') {
1321  $sql = 'SET FOREIGN_KEY_CHECKS=0';
1322  print '<!-- '.$sql.' -->';
1323  $resql = $db->query($sql);
1324  }
1325 
1326  foreach ($listoftables as $table) {
1327  // do not convert llx_const if mysql encrypt/decrypt is used
1328  if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1329  continue;
1330  }
1331  if ($table[1] == 'VIEW') {
1332  print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1333  continue;
1334  }
1335 
1336  print '<tr><td colspan="2">';
1337  print $table[0];
1338  $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1339  $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
1340  print '<!-- '.$sql1.' -->';
1341  print '<!-- '.$sql2.' -->';
1342  if ($force_utf8mb4_on_tables == 'confirmed') {
1343  $resql1 = $db->query($sql1);
1344  if ($resql1) {
1345  $resql2 = $db->query($sql2);
1346  } else {
1347  $resql2 = false;
1348  }
1349  print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
1350  } else {
1351  print ' - Disabled';
1352  }
1353  print '</td></tr>';
1354  flush();
1355  ob_flush();
1356  }
1357 
1358  // Enable foreign key checking
1359  if ($force_utf8mb4_on_tables == 'confirmed') {
1360  $sql = 'SET FOREIGN_KEY_CHECKS=1';
1361  print '<!-- '.$sql.' -->';
1362  $resql = $db->query($sql);
1363  }
1364  } else {
1365  print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1366  }
1367 }
1368 
1369 // rebuild sequences for pgsql
1370 if ($ok && GETPOST('rebuild_sequences', 'alpha')) {
1371  print '<tr><td colspan="2"><br>*** Force to rebuild sequences (for postgresql only)</td></tr>';
1372 
1373  if ($db->type == "pgsql") {
1374  $rebuild_sequence = GETPOST('rebuild_sequences', 'alpha');
1375 
1376  if ($rebuild_sequence == 'confirmed') {
1377  $sql = "SELECT dol_util_rebuild_sequences();";
1378  print '<!-- '.$sql.' -->';
1379  $resql = $db->query($sql);
1380  }
1381  } else {
1382  print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1383  }
1384 }
1385 
1386 //
1387 if ($ok && GETPOST('repair_link_dispatch_lines_supplier_order_lines')) {
1388  /*
1389  * This script is meant to be run when upgrading from a dolibarr version < 3.8
1390  * to a newer version.
1391  *
1392  * Version 3.8 introduces a new column in llx_commande_fournisseur_dispatch, which
1393  * matches the dispatch to a specific supplier order line (so that if there are
1394  * several with the same product, the user can specifically tell which products of
1395  * which line were dispatched where).
1396  *
1397  * However when migrating, the new column has a default value of 0, which means that
1398  * old supplier orders whose lines were dispatched using the old dolibarr version
1399  * have unspecific dispatch lines, which are not taken into account by the new version,
1400  * thus making the order look like it was never dispatched at all.
1401  *
1402  * This scripts sets this foreign key to the first matching supplier order line whose
1403  * product (and supplier order of course) are the same as the dispatch’s.
1404  *
1405  * If the dispatched quantity is more than indicated on the order line (this happens if
1406  * there are several order lines for the same product), it creates new dispatch lines
1407  * pointing to the other order lines accordingly, until all the dispatched quantity is
1408  * accounted for.
1409  */
1410 
1411  $repair_link_dispatch_lines_supplier_order_lines = GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha');
1412 
1413 
1414  echo '<tr><th>Repair llx_commande_fournisseur_dispatch.fk_commandefourndet</th></tr>';
1415  echo '<tr><td>Repair in progress. This may take a while.</td></tr>';
1416 
1417  $sql_dispatch = 'SELECT * FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch WHERE COALESCE(fk_commandefourndet, 0) = 0';
1418  $db->begin();
1419  $resql_dispatch = $db->query($sql_dispatch);
1420  $n_processed_rows = 0;
1421  $errors = array();
1422  if ($resql_dispatch) {
1423  if ($db->num_rows($resql_dispatch) == 0) {
1424  echo '<tr><td>Nothing to do.</td></tr>';
1425  exit;
1426  }
1427  while ($obj_dispatch = $db->fetch_object($resql_dispatch)) {
1428  $sql_line = 'SELECT line.rowid, line.qty FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet AS line';
1429  $sql_line .= ' WHERE line.fk_commande = '.((int) $obj_dispatch->fk_commande);
1430  $sql_line .= ' AND line.fk_product = '.((int) $obj_dispatch->fk_product);
1431  $resql_line = $db->query($sql_line);
1432 
1433  // s’il y a plusieurs lignes avec le même produit sur cette commande fournisseur,
1434  // on divise la ligne de dispatch en autant de lignes qu’on en a sur la commande pour le produit
1435  // et on met la quantité de la ligne dans la limite du "budget" indiqué par dispatch.qty
1436 
1437  $remaining_qty = $obj_dispatch->qty;
1438  $first_iteration = true;
1439  if (!$resql_line) {
1440  echo '<tr><td>Unable to find a matching supplier order line for dispatch #'.$obj_dispatch->rowid.'</td></tr>';
1441  $errors[] = $sql_line;
1442  $n_processed_rows++;
1443  continue;
1444  }
1445  if ($db->num_rows($resql_line) == 0) {
1446  continue;
1447  }
1448  while ($obj_line = $db->fetch_object($resql_line)) {
1449  if (!$remaining_qty) {
1450  break;
1451  }
1452  if (!$obj_line->rowid) {
1453  continue;
1454  }
1455  $qty_for_line = min($remaining_qty, $obj_line->qty);
1456  if ($first_iteration) {
1457  $sql_attach = 'UPDATE '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
1458  $sql_attach .= ' SET fk_commandefourndet = '.((int) $obj_line->rowid).', qty = '.((float) $qty_for_line);
1459  $sql_attach .= ' WHERE rowid = '.((int) $obj_dispatch->rowid);
1460  $first_iteration = false;
1461  } else {
1462  $sql_attach_values = array(
1463  ((int) $obj_dispatch->fk_commande),
1464  ((int) $obj_dispatch->fk_product),
1465  ((int) $obj_line->rowid),
1466  ((float) $qty_for_line),
1467  ((int) $obj_dispatch->fk_entrepot),
1468  ((int) $obj_dispatch->fk_user),
1469  $obj_dispatch->datec ? "'".$db->idate($db->jdate($obj_dispatch->datec))."'" : 'NULL',
1470  $obj_dispatch->comment ? "'".$db->escape($obj_dispatch->comment)."'" : 'NULL',
1471  $obj_dispatch->status ? ((int) $obj_dispatch->status) : 'NULL',
1472  $obj_dispatch->tms ? "'".$db->idate($db->jdate($obj_dispatch->tms))."'" : 'NULL',
1473  $obj_dispatch->batch ? "'".$db->escape($obj_dispatch->batch)."'" : 'NULL',
1474  $obj_dispatch->eatby ? "'".$db->escape($obj_dispatch->eatby)."'" : 'NULL',
1475  $obj_dispatch->sellby ? "'".$db->escape($obj_dispatch->sellby)."'" : 'NULL'
1476  );
1477  $sql_attach_values = join(', ', $sql_attach_values);
1478 
1479  $sql_attach = 'INSERT INTO '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch';
1480  $sql_attach .= ' (fk_commande, fk_product, fk_commandefourndet, qty, fk_entrepot, fk_user, datec, comment, status, tms, batch, eatby, sellby)';
1481  $sql_attach .= " VALUES (".$sql_attach_values.")";
1482  }
1483 
1484  if ($repair_link_dispatch_lines_supplier_order_lines == 'confirmed') {
1485  $resql_attach = $db->query($sql_attach);
1486  } else {
1487  $resql_attach = true; // Force success in test mode
1488  }
1489 
1490  if ($resql_attach) {
1491  $remaining_qty -= $qty_for_line;
1492  } else {
1493  $errors[] = $sql_attach;
1494  }
1495 
1496  $first_iteration = false;
1497  }
1498  $n_processed_rows++;
1499 
1500  // report progress every 256th row
1501  if (!($n_processed_rows & 0xff)) {
1502  echo '<tr><td>Processed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1503  flush();
1504  ob_flush();
1505  }
1506  }
1507  } else {
1508  echo '<tr><td>Unable to find any dispatch without an fk_commandefourndet.'."</td></tr>\n";
1509  echo $sql_dispatch."\n";
1510  }
1511  echo '<tr><td>Fixed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1512  echo '<tr><td>DONE.'."</td></tr>\n";
1513 
1514  if (count($errors)) {
1515  $db->rollback();
1516  echo '<tr><td>The transaction was rolled back due to errors: nothing was changed by the script.</td></tr>';
1517  } else {
1518  $db->commit();
1519  }
1520  $db->close();
1521 
1522  echo '<tr><td><h3>SQL queries with errors:</h3></tr></td>';
1523  echo '<tr><td>'.join('</td></tr><tr><td>', $errors).'</td></tr>';
1524 }
1525 
1526 // Repair llx_commande_fournisseur to eleminate duplicate reference
1527 if ($ok && GETPOST('repair_supplier_order_duplicate_ref')) {
1528  require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php';
1529  include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1530 
1531  $db->begin();
1532 
1533  $err = 0;
1534 
1535  // Query to find all duplicate supplier orders
1536  $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
1537  $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)";
1538 
1539  // Build a list of ref => []CommandeFournisseur
1540  $duplicateSupplierOrders = [];
1541  $resql = $db->query($sql);
1542  if ($resql) {
1543  while ($rawSupplierOrder = $db->fetch_object($resql)) {
1544  $supplierOrder = new CommandeFournisseur($db);
1545  $supplierOrder->setVarsFromFetchObj($rawSupplierOrder);
1546 
1547  $duplicateSupplierOrders[$rawSupplierOrder->ref] [] = $supplierOrder;
1548  }
1549  } else {
1550  $err++;
1551  }
1552 
1553  // Process all duplicate supplier order and regenerate the reference for all except the first one
1554  foreach ($duplicateSupplierOrders as $ref => $supplierOrders) {
1556  foreach (array_slice($supplierOrders, 1) as $supplierOrder) {
1557  // Definition of supplier order numbering model name
1558  $soc = new Societe($db);
1559  $soc->fetch($supplierOrder->fourn_id);
1560 
1561  $newRef = $supplierOrder->getNextNumRef($soc);
1562 
1563  $sql = "UPDATE " . MAIN_DB_PREFIX . "commande_fournisseur cf SET cf.ref = '" . $db->escape($newRef) . "' WHERE cf.rowid = " . (int) $supplierOrder->id;
1564  if (!$db->query($sql)) {
1565  $err++;
1566  }
1567  }
1568  }
1569 
1570  if ($err == 0) {
1571  $db->commit();
1572  } else {
1573  $db->rollback();
1574  }
1575 }
1576 
1577 print '</table>';
1578 
1579 
1580 
1581 if (empty($actiondone)) {
1582  print '<div class="error">'.$langs->trans("ErrorWrongParameters").'</div>';
1583 }
1584 
1585 if ($oneoptionset) {
1586  print '<div class="center" style="padding-top: 10px"><a href="../index.php?mainmenu=home&leftmenu=home'.(GETPOSTISSET("login") ? '&username='.urlencode(GETPOST("login")) : '').'">';
1587  print $langs->trans("GoToDolibarr");
1588  print '</a></div>';
1589 } else {
1590  print '<div class="center warning" style="padding-top: 10px">';
1591  print $langs->trans("SetAtLeastOneOptionAsUrlParameter");
1592  print '</div>';
1593 }
1594 
1595 dolibarr_install_syslog("--- repair: end");
1596 pFooter(1, $setuplang);
1597 
1598 if ($db->connected) {
1599  $db->close();
1600 }
1601 
1602 // Return code if ran from command line
1603 if (!$ok && isset($argv[1])) {
1604  exit(1);
1605 }
run_sql($sqlfile, $silent=1, $entity=0, $usesavepoint=1, $handler='', $okerror='default', $linelengthlimit=32768, $nocommentremoval=0, $offsetforchartofaccount=0, $colspan=0, $onlysqltoimportwebsite=0, $database='')
Launch a sql file.
Definition: admin.lib.php:169
Classe permettant la gestion des paiements des charges La tva collectee n'est calculee que sur les fa...
Class to manage predefined suppliers products.
Class to manage customers orders.
Class to manage contracts.
Class to manage standard extra fields.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
Definition: files.lib.php:1356
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
Definition: files.lib.php:1482
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:483
dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:717
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:62
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
vignette($file, $maxWidth=160, $maxHeight=120, $extName='_small', $quality=50, $outdir='thumbs', $targetformat=0)
Create a thumbnail from an image file (Supported extensions are gif, jpg, png and bmp).
Definition: images.lib.php:509
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
Definition: images.lib.php:80
pHeader($subtitle, $next, $action='set', $param='', $forcejqueryurl='', $csstable='main-inside')
Show HTML header of install pages.
Definition: inc.php:513
pFooter($nonext=0, $setuplang='', $jscheckfunction='', $withpleasewait=0, $morehtml='')
Print HTML footer of install pages.
Definition: inc.php:602
dolibarr_install_syslog($message, $level=LOG_DEBUG)
Log function for install pages.
Definition: inc.php:663
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
div float
Buy price without taxes.
Definition: style.css.php:926
clean_data_ecm_directories()
Clean data into ecm_directories table.
Definition: repair.lib.php:130
dol_decode($chain, $key='1')
Decode a base 64 encoded + specific delta change.