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