dolibarr 23.0.4
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-2025 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
8 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 Vincent de Grandpré <vincent@de-grandpre.quebec>
10 * Copyright (C) 2025 Alexandre Spangaro <alexandre@inovea-conseil.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
31include_once 'inc.php';
32
47if (file_exists($conffile)) {
48 include_once $conffile;
49}
50
51'
52@phan-var-force ?string $dolibarr_main_db_encryption
53@phan-var-force ?string $dolibarr_main_db_cryptkey
54';
55
56require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php';
57include_once $dolibarr_main_document_root.'/core/lib/images.lib.php';
58require_once $dolibarr_main_document_root.'/core/class/extrafields.class.php';
59require_once $dolibarr_main_document_root.'/core/class/html.form.class.php';
60require_once 'lib/repair.lib.php';
61
62$ok = 0;
63
64
65// This page may be long. We are increasing the time allowed.
66// Only works if not in safe_mode.
67$err = error_reporting();
68error_reporting(0);
69@set_time_limit(120);
70error_reporting($err);
71
72$setuplang = GETPOST("selectlang", 'aZ09', 3) ? GETPOST("selectlang", 'aZ09', 3) : 'auto';
73$langs->setDefaultLang($setuplang);
74
75$langs->loadLangs(array("admin", "install", "other"));
76
77if ($dolibarr_main_db_type == "mysqli") {
78 $choix = 1;
79}
80if ($dolibarr_main_db_type == "pgsql") {
81 $choix = 2;
82}
83if ($dolibarr_main_db_type == "mssql") {
84 $choix = 3;
85}
86
87
88dolibarr_install_syslog("--- repair: entering upgrade.php page");
89if (!is_object($conf)) {
90 dolibarr_install_syslog("repair: conf file not initialized", LOG_ERR);
91}
92
93
94// This page runs on the install bootstrap, which never sets $user.
95// dol_delete_file() -> EcmFiles::delete(User $user) requires a User,
96// so we force an empty one here, before any action that may need it.
97require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
98$user = new User($db);
99
100
101/*
102 * View
103 */
104
105$form = new Form($db);
106
107pHeader($langs->trans("Repair"), "upgrade2", GETPOST('action', 'aZ09'));
108
109// Action to launch the repair script
110$actiondone = 1;
111
112
113print '<table cellspacing="0" cellpadding="1" class="centpercent">';
114$error = 0;
115
116// If password is encoded, we decode it
117if (preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
118 require_once $dolibarr_main_document_root.'/core/lib/security.lib.php';
119 if (preg_match('/crypted:/i', $dolibarr_main_db_pass)) {
120 $dolibarr_main_db_pass = preg_replace('/crypted:/i', '', $dolibarr_main_db_pass);
121 $dolibarr_main_db_encrypted_pass = $dolibarr_main_db_pass; // We need to set this as it is used to know the password was initially encrypted
122 $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_pass);
123 } elseif (preg_match('/dolcrypt:/i', $dolibarr_main_db_pass)) {
124 $dolibarr_main_db_encrypted_pass = $dolibarr_main_db_pass; // We need to set this as it is used to know the password was initially encrypted
125 $dolibarr_main_db_pass = dolDecrypt($dolibarr_main_db_pass);
126 } else {
127 $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
128 }
129}
130
131// $conf is already instancied inside inc.php
132$conf->db->type = $dolibarr_main_db_type;
133$conf->db->host = $dolibarr_main_db_host;
134$conf->db->port = $dolibarr_main_db_port;
135$conf->db->name = $dolibarr_main_db_name;
136$conf->db->user = $dolibarr_main_db_user;
137$conf->db->pass = $dolibarr_main_db_pass;
138
139// For encryption
140$conf->db->dolibarr_main_db_encryption = isset($dolibarr_main_db_encryption) ? $dolibarr_main_db_encryption : 0;
141$conf->db->dolibarr_main_db_cryptkey = isset($dolibarr_main_db_cryptkey) ? $dolibarr_main_db_cryptkey : '';
142
143$db = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, (int) $conf->db->port);
144
145if ($db->connected) {
146 print '<tr><td class="nowrap">';
147 print $langs->trans("ServerConnection")." : ".$dolibarr_main_db_host.'</td><td class="right">'.$langs->trans("OK")."</td></tr>";
148 dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerConnection").": ".$dolibarr_main_db_host.$langs->transnoentities("OK"));
149 $ok = 1;
150} else {
151 print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name).'</td><td class="right">'.$langs->transnoentities("Error")."</td></tr>";
152 dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
153 $ok = 0;
154}
155
156if ($ok) {
157 if ($db->database_selected) {
158 print '<tr><td class="nowrap">';
159 print $langs->trans("DatabaseConnection")." : ".$dolibarr_main_db_name.'</td><td class="right">'.$langs->trans("OK")."</td></tr>";
160 dolibarr_install_syslog("repair: database connection successful: ".$dolibarr_main_db_name);
161 $ok = 1;
162 } else {
163 print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name).'</td><td class="right">'.$langs->trans("Error")."</td></tr>";
164 dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
165 $ok = 0;
166 }
167}
168
169// Show database version
170if ($ok) {
171 $version = $db->getVersion();
172 $versionarray = $db->getVersionArray();
173 print '<tr><td>'.$langs->trans("ServerVersion").'</td>';
174 print '<td class="right">'.$version.'</td></tr>';
175 dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerVersion").": ".$version);
176 //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
177}
178
179print '</table>';
180
181
182print '<br>';
183
184
185print '<div class="warning" style="padding-top: 10px">';
186print 'Select a link "test" or "confirmed" to launch a reparation on the chosen option...';
187print '</div>';
188print '<br>';
189
190
191print '<table class="liste centpercent" style="border: 1px solid #ccc">';
192print '<tr>';
193print '<th>Option</th>';
194print '<th>Information</th>';
195print '<th>Launch test</th>';
196print '<th>Launch confirmed</th>';
197print '</tr>';
198
199$warning_using_utf8mb4 = '';
200if ($dolibarr_main_db_character_set != 'utf8mb4') {
201 $warning_using_utf8mb4 = '<img src="../theme/eldy/img/warning.png" class="pictofortooltip valignmiddle" title="If you switch to utf8mb4, you must also check the value for $dolibarr_main_db_character_set and $dolibarr_main_db_collation into conf/conf.php file.">';
202}
203
204$sections = [
205 'Standard' => [
206 [
207 'name' => 'standard',
208 'info' => ''
209 ]
210 ],
211 'Modules' => [
212 [
213 'name' => 'force_disable_of_modules_not_found',
214 'info' => 'Disable modules not found'
215 ]
216 ],
217 'Files' => [
218 [
219 'name' => 'restore_thirdparties_logos',
220 'info' => 'Restore logos for thirdparties'
221 ],
222 [
223 'name' => 'restore_user_pictures',
224 'info' => 'Restore user pictures'
225 ],
226 [
227 'name' => 'rebuild_product_thumbs',
228 'info' => 'Rebuild product thumbnails'
229 ],
230 [
231 'name' => 'repair_mailing_path',
232 'info' => 'Repair path of mailing files',
233 'tooltip' => 'Should be applied when using emailing module with > 99 mailings. In that case, please also set MAILING_USE_NEW_PATH_FOR_FILES.'
234 ]
235 ],
236 'Clean tables and data' => [
237 [
238 'name' => 'clean_linked_elements',
239 'info' => 'Clean linked elements'
240 ],
241 [
242 'name' => 'clean_menus',
243 'info' => 'Clean menus'
244 ],
245 [
246 'name' => 'clean_orphelin_dir',
247 'info' => 'Clean orphan directories'
248 ],
249 [
250 'name' => 'clean_product_stock_batch',
251 'info' => 'Clean product stock batch'
252 ],
253 [
254 'name' => 'clean_perm_table',
255 'info' => 'Clean permissions table'
256 ],
257 [
258 'name' => 'clean_ecm_files_table',
259 'info' => 'Clean ECM files table'
260 ],
261 [
262 'name' => 'repair_link_dispatch_lines_supplier_order_lines',
263 'info' => 'Repair link between dispatch lines and supplier order lines'
264 ]
265 ],
266 'Init data' => [
267 [
268 'name' => 'set_empty_time_spent_amount',
269 'info' => 'Init empty time spent amount'
270 ]
271 ],
272 'Structure' => [
273 [
274 'name' => 'force_utf8_on_tables',
275 'info' => 'Force utf8 + row=dynamic, for mysql/mariadb only'
276 ],
277 [
278 'name' => 'force_utf8mb4_on_tables',
279 'info' => 'Force utf8mb4 + row=dynamic, for mysql/mariadb only' . $warning_using_utf8mb4
280 ],
281 [
282 'name' => 'force_collation_from_conf_on_tables',
283 'info' => 'Force '.$conf->db->character_set.'/'.$conf->db->dolibarr_main_db_collation.' + row=dynamic, for mysql/mariadb only'
284 ]
285 ],
286 'Rebuild sequence' => [
287 [
288 'name' => 'rebuild_sequences',
289 'info' => 'For postgresql only'
290 ]
291 ]
292];
293
294$conf->use_javascript_ajax = 1;
295
296foreach ($sections as $section => $options) {
297 print '<tr style="background:#f4f4f4;font-weight:bold"><td colspan="5">'.$section.'</td></tr>';
298 foreach ($options as $opt) {
299 $option = $opt['name'];
300 $info = $opt['info'];
301 $tooltip = empty($opt['tooltip']) ? '' : $opt['tooltip'];
302 $value = GETPOST($option, 'alpha') ? GETPOST($option, 'alpha') : 'undefined';
303 // Generate links with the right option and value
304 $url_test = $_SERVER['PHP_SELF'].'?'.$option.'=test';
305 $url_confirmed = $_SERVER['PHP_SELF'].'?'.$option.'=confirmed';
306 print '<tr>';
307 print '<td>' . $option . '</td>';
308 print '<td>';
309 if ($tooltip) {
310 print $form->textwithpicto($info, $tooltip);
311 } else {
312 print $info;
313 }
314 print '</td>';
315 print '<td class="center"><a href="'.$url_test.'" title="Launch test on option '.$option.'">test</a>'.($value == 'test' ? ' (X)' : '').'</td>';
316 print '<td class="center"><a href="'.$url_confirmed.'" title="Launch confirmed on option '.$option.'">confirmed</a>'.($value == 'confirmed' ? ' (X)' : '').'</td>';
317 print '</tr>';
318 }
319}
320print '</table>';
321
322
323print '<br id="sectionresult">';
324print '<br>';
325
326
327$conf->setValues($db);
328// Reset forced setup after the setValues
329if (defined('SYSLOG_FILE')) {
330 $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
331}
332$conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
333
334
335/* Start action here */
336$oneoptionset = 0;
337$oneoptionset = (GETPOST('standard', 'alpha') || GETPOST('restore_thirdparties_logos', 'alpha') || GETPOST('clean_linked_elements', 'alpha') || GETPOST('clean_menus', 'alpha')
338 || GETPOST('clean_orphelin_dir', 'alpha') || GETPOST('clean_product_stock_batch', 'alpha') || GETPOST('set_empty_time_spent_amount', 'alpha') || GETPOST('rebuild_product_thumbs', 'alpha')
339 || GETPOST('clean_perm_table', 'alpha') || GETPOST('clean_ecm_files_table', 'alpha')
340 || GETPOST('force_disable_of_modules_not_found', 'alpha')
341 || GETPOST('force_utf8_on_tables', 'alpha') || GETPOST('force_utf8mb4_on_tables', 'alpha') || GETPOST('force_collation_from_conf_on_tables', 'alpha')
342 || GETPOST('rebuild_sequences', 'alpha') || GETPOST('recalculateinvoicetotal', 'alpha')) || GETPOST('repair_mailing_path', 'alpha');
343
344if ($ok && $oneoptionset) {
345 // Show wait message
346 print $langs->trans("PleaseBePatient").'<br><br>';
347
348 // Flush (some browser need a certain amount of data)
349 print str_repeat(' ', 1024);
350 ob_flush();
351 flush();
352}
353
354
355
356print '<table cellspacing="0" cellpadding="1" class="centpercent">';
357
358// run_sql: Run repair SQL file
359if ($ok && GETPOST('standard', 'alpha')) {
360 $dir = "mysql/migration/";
361
362 $filelist = array();
363 $i = 0;
364 $ok = 0;
365
366 // Recupere list fichier
367 $filesindir = array();
368 $handle = opendir($dir);
369 if (is_resource($handle)) {
370 while (($file = readdir($handle)) !== false) {
371 if (preg_match('/\.sql$/i', $file)) {
372 $filesindir[] = $file;
373 }
374 }
375 }
376 sort($filesindir);
377
378 foreach ($filesindir as $file) {
379 if (preg_match('/repair/i', $file)) {
380 $filelist[] = $file;
381 }
382 }
383
384 // Loop on each file
385 foreach ($filelist as $file) {
386 print '<tr><td class="nowrap">*** ';
387 print $langs->trans("Script").'</td><td class="right">'.$file.'</td></tr>';
388
389 $name = substr($file, 0, dol_strlen($file) - 4);
390
391 // Run sql script
392 $ok = run_sql($dir.$file, 0, 0, 1);
393 }
394}
395
396
397// sync_extrafields: Search list of fields declared and list of fields created into databases, then create fields missing
398
399if ($ok && GETPOST('standard', 'alpha')) {
400 require_once DOL_DOCUMENT_ROOT.'/contrat/class/contratligne.class.php';
401
402 print '<tr><td colspan="2"><br>*** Update denormalized_lower_planned_end_date.</td></tr>';
403 $sqltoupdatecontract = "UPDATE ".MAIN_DB_PREFIX."contrat";
404 $sqltoupdatecontract .= " SET denormalized_lower_planned_end_date = (SELECT MIN(date_fin_validite) FROM ".MAIN_DB_PREFIX."contratdet as cd WHERE cd.fk_contrat = c.rowid AND cd.statut = ".ContratLigne::STATUS_OPEN.")";
405 $resqltoupdatecontract = $db->query($sqltoupdatecontract);
406
407 $extrafields = new ExtraFields($db);
408
409 // List of tables that has an extrafield table
410 $listofmodulesextra = array('societe' => 'societe', 'adherent' => 'adherent', 'product' => 'product',
411 'socpeople' => 'socpeople', 'propal' => 'propal', 'commande' => 'commande',
412 'facture' => 'facture', 'facturedet' => 'facturedet', 'facture_rec' => 'facture_rec', 'facturedet_rec' => 'facturedet_rec',
413 'supplier_proposal' => 'supplier_proposal', 'commande_fournisseur' => 'commande_fournisseur',
414 'facture_fourn' => 'facture_fourn', 'facture_fourn_rec' => 'facture_fourn_rec', 'facture_fourn_det' => 'facture_fourn_det', 'facture_fourn_det_rec' => 'facture_fourn_det_rec',
415 'fichinter' => 'fichinter', 'fichinterdet' => 'fichinterdet',
416 'inventory' => 'inventory',
417 'actioncomm' => 'actioncomm', 'bom_bom' => 'bom_bom', 'mrp_mo' => 'mrp_mo',
418 'adherent_type' => 'adherent_type', 'user' => 'user', 'partnership' => 'partnership', 'projet' => 'projet', 'projet_task' => 'projet_task', 'ticket' => 'ticket');
419 //$listofmodulesextra = array('fichinter'=>'fichinter');
420
421 print '<tr><td colspan="2"><br>*** Check that fields into the extra table structure match the table of definition. If not, add column into table</td></tr>';
422 foreach ($listofmodulesextra as $tablename => $elementtype) {
423 // Get list of fields
424 $tableextra = MAIN_DB_PREFIX.$tablename.'_extrafields';
425
426 // Define $arrayoffieldsdesc
427 $arrayoffieldsdesc = $extrafields->fetch_name_optionals_label($elementtype);
428
429 // Define $arrayoffieldsfound
430 $arrayoffieldsfound = array();
431 $resql = $db->DDLDescTable($tableextra);
432 if ($resql) {
433 print '<tr><td>Check availability of extra field for '.$tableextra;
434 $i = 0;
435 while ($obj = $db->fetch_object($resql)) {
436 $fieldname = $fieldtype = '';
437 if (preg_match('/mysql/', $db->type)) {
438 $fieldname = $obj->Field;
439 $fieldtype = $obj->Type;
440 } else {
441 $fieldname = isset($obj->Key) ? $obj->Key : $obj->attname;
442 $fieldtype = isset($obj->Type) ? $obj->Type : 'varchar';
443 }
444
445 if (empty($fieldname)) {
446 continue;
447 }
448 if (in_array($fieldname, array('rowid', 'tms', 'fk_object', 'import_key'))) {
449 continue;
450 }
451 $arrayoffieldsfound[$fieldname] = array('type' => $fieldtype);
452 }
453 print ' - Found '.count($arrayoffieldsfound).' fields into table';
454 if (count($arrayoffieldsfound) > 0) {
455 print ' <span class="opacitymedium">('.implode(', ', array_keys($arrayoffieldsfound)).')</span>';
456 }
457 print '<br>'."\n";
458
459 // If it does not match, we create fields
460 foreach ($arrayoffieldsdesc as $code => $label) {
461 if (!in_array($code, array_keys($arrayoffieldsfound))) {
462 print 'Found field '.$code.' declared into '.MAIN_DB_PREFIX.'extrafields table but not found into desc of table '.$tableextra." -> ";
463 $type = $extrafields->attributes[$elementtype]['type'][$code];
464 $length = $extrafields->attributes[$elementtype]['size'][$code];
465 $attribute = '';
466 $default = '';
467 $extra = '';
468 $null = 'null';
469
470 if ($type == 'boolean') {
471 $typedb = 'int';
472 $lengthdb = '1';
473 } elseif ($type == 'price') {
474 $typedb = 'double';
475 $lengthdb = '24,8';
476 } elseif ($type == 'phone') {
477 $typedb = 'varchar';
478 $lengthdb = '20';
479 } elseif ($type == 'mail') {
480 $typedb = 'varchar';
481 $lengthdb = '128';
482 } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
483 $typedb = 'text';
484 $lengthdb = '';
485 } elseif ($type == 'link') {
486 $typedb = 'int';
487 $lengthdb = '11';
488 } else {
489 $typedb = $type;
490 $lengthdb = $length;
491 }
492
493 $field_desc = array(
494 'type' => $typedb,
495 'value' => $lengthdb,
496 'attribute' => $attribute,
497 'default' => $default,
498 'extra' => $extra,
499 'null' => $null
500 );
501 //var_dump($field_desc);exit;
502
503 $result = 0;
504 if (GETPOST('standard', 'alpha') == 'confirmed') {
505 $result = $db->DDLAddField($tableextra, $code, $field_desc, "");
506
507 if ($result < 0) {
508 print "KO ".$db->lasterror."<br>\n";
509 } else {
510 print "OK<br>\n";
511 }
512 } else {
513 print ' - Mode test, no column added.';
514 }
515 }
516 }
517
518 print "</td><td>&nbsp;</td></tr>\n";
519 } else {
520 print '<tr><td>Table '.$tableextra.' is not found</td><td></td></tr>'."\n";
521 }
522 }
523}
524
525
526// clean_data_ecm_dir: Clean data into ecm_directories table
527if ($ok && GETPOST('standard', 'alpha')) {
529}
530
531
532// clean declaration constants
533if ($ok && GETPOST('standard', 'alpha')) {
534 print '<tr><td colspan="2"><br>*** Clean constant record of modules not enabled</td></tr>';
535
536 $sql = "SELECT name, entity, value";
537 $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
538 $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'";
539 $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'";
540 $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_%'";
541 $sql .= " OR name LIKE 'MAIN_MODULE_%_MODULEFOREXTERNAL'";
542 $sql .= " ORDER BY name, entity";
543
544 $resql = $db->query($sql);
545 if ($resql) {
546 $num = $db->num_rows($resql);
547
548 if ($num) {
549 $db->begin();
550
551 $i = 0;
552 while ($i < $num) {
553 $obj = $db->fetch_object($resql);
554
555 $reg = array();
556 if (preg_match('/MAIN_MODULE_([^_]+)_(.+)/i', $obj->name, $reg)) {
557 $name = $reg[1];
558 $type = $reg[2];
559
560 $sql2 = "SELECT COUNT(*) as nb";
561 $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
562 $sql2 .= " WHERE name = 'MAIN_MODULE_".$name."'";
563 $sql2 .= " AND entity = ".((int) $obj->entity);
564 $resql2 = $db->query($sql2);
565 if ($resql2) {
566 $obj2 = $db->fetch_object($resql2);
567 if ($obj2 && $obj2->nb == 0) {
568 // Module not found, so we can remove entry
569 $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = '".$db->escape($obj->name)."' AND entity = ".((int) $obj->entity);
570
571 if (GETPOST('standard', 'alpha') == 'confirmed') {
572 $db->query($sqldelete);
573
574 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>';
575 } else {
576 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>';
577 }
578 } else {
579 //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>';
580 }
581 }
582 }
583
584 $i++;
585 }
586
587 $db->commit();
588 }
589 } else {
590 dol_print_error($db);
591 }
592}
593
594
595// clean box of not enabled modules
596if ($ok && GETPOST('standard', 'alpha')) {
597 print '<tr><td colspan="2"><br>*** Clean definition of boxes of modules not enabled</td></tr>';
598
599 $sql = "SELECT file, entity FROM ".MAIN_DB_PREFIX."boxes_def";
600 $sql .= " WHERE file like '%@%'";
601
602 $resql = $db->query($sql);
603 if ($resql) {
604 $num = $db->num_rows($resql);
605
606 if ($num) {
607 $db->begin();
608
609 $i = 0;
610 while ($i < $num) {
611 $obj = $db->fetch_object($resql);
612
613 $reg = array();
614 if (preg_match('/^(.+)@(.+)$/i', $obj->file, $reg)) {
615 $name = $reg[1];
616 $module = $reg[2];
617
618 $sql2 = "SELECT COUNT(*) as nb";
619 $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
620 $sql2 .= " WHERE name = 'MAIN_MODULE_".strtoupper($module)."'";
621 $sql2 .= " AND entity = ".((int) $obj->entity);
622 $sql2 .= " AND value <> 0";
623 $resql2 = $db->query($sql2);
624 if ($resql2) {
625 $obj2 = $db->fetch_object($resql2);
626 if ($obj2 && $obj2->nb == 0) {
627 // Module not found, so we canremove entry
628 $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).")";
629 $sqldeleteb = "DELETE FROM ".MAIN_DB_PREFIX."boxes_def WHERE file = '".$db->escape($obj->file)."' AND entity = ".((int) $obj->entity);
630
631 if (GETPOST('standard', 'alpha') == 'confirmed') {
632 $db->query($sqldeletea);
633 $db->query($sqldeleteb);
634
635 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>';
636 } else {
637 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>';
638 }
639 } else {
640 //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>';
641 }
642 }
643 }
644
645 $i++;
646 }
647
648 $db->commit();
649 }
650 }
651}
652
653
654// restore_thirdparties_logos: Move logos to correct new directory.
655if ($ok && GETPOST('restore_thirdparties_logos')) {
656 //$exts=array('gif','png','jpg');
657
658 $ext = '';
659
660 print '<tr><td colspan="2"><br>*** Restore thirdparties logo<br>';
661
662 $sql = "SELECT s.rowid, s.nom as name, s.logo FROM ".MAIN_DB_PREFIX."societe as s ORDER BY s.nom";
663 $resql = $db->query($sql);
664 if ($resql) {
665 $num = $db->num_rows($resql);
666 $i = 0;
667
668 while ($i < $num) {
669 $obj = $db->fetch_object($resql);
670
671 /*
672 $name=preg_replace('/é/','',$obj->name);
673 $name=preg_replace('/ /','_',$name);
674 $name=preg_replace('/\'/','',$name);
675 */
676
677 $tmp = explode('.', (string) $obj->logo);
678 $name = $tmp[0];
679 if (isset($tmp[1])) {
680 $ext = '.'.$tmp[1];
681 }
682
683 if (!empty($name)) {
684 $filetotest = $dolibarr_main_data_root.'/societe/logos/'.$name.$ext;
685 $filetotestsmall = $dolibarr_main_data_root.'/societe/logos/thumbs/'.$name.'_small'.$ext;
686 $exists = (int) dol_is_file($filetotest);
687 print 'Check thirdparty '.$obj->rowid.' name='.$obj->name.' logo='.$obj->logo.' file '.$filetotest." exists=".$exists."<br>\n";
688 if ($exists) {
689 $filetarget = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/'.$name.$ext;
690 $filetargetsmall = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs/'.$name.'_small'.$ext;
691 $existt = dol_is_file($filetarget);
692 if (!$existt) {
693 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
694 dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos');
695 }
696
697 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
698 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
699 dol_copy($filetotest, $filetarget, '', 0);
700 }
701 }
702
703 $existtt = dol_is_file($filetargetsmall);
704 if (!$existtt) {
705 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
706 dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs');
707 }
708 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
709 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
710 dol_copy($filetotestsmall, $filetargetsmall, '', 0);
711 }
712 }
713 }
714 }
715
716 $i++;
717 }
718 } else {
719 $ok = 0;
720 dol_print_error($db);
721 }
722
723 print '</td></tr>';
724}
725
726
727
728// restore_user_pictures: Move pictures to correct new directory.
729if ($ok && GETPOST('restore_user_pictures', 'alpha')) {
730 //$exts=array('gif','png','jpg');
731
732 $ext = '';
733
734 print '<tr><td colspan="2"><br>*** Restore user pictures<br>';
735
736 $sql = "SELECT s.rowid, s.firstname, s.lastname, s.login, s.photo FROM ".MAIN_DB_PREFIX."user as s ORDER BY s.rowid";
737 $resql = $db->query($sql);
738 if ($resql) {
739 $num = $db->num_rows($resql);
740 $i = 0;
741
742 while ($i < $num) {
743 $obj = $db->fetch_object($resql);
744
745 /*
746 $name=preg_replace('/é/','',$obj->name);
747 $name=preg_replace('/ /','_',$name);
748 $name=preg_replace('/\'/','',$name);
749 */
750
751 $tmp = explode('.', (string) $obj->photo);
752 $name = $tmp[0];
753 if (isset($tmp[1])) {
754 $ext = '.'.$tmp[1];
755 }
756
757 if (!empty($name)) {
758 $filetotest = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/'.$name.$ext;
759 $filetotestsmall = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_small'.$ext;
760 $filetotestmini = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_mini'.$ext;
761 $exists = (int) dol_is_file($filetotest);
762 print 'Check user '.$obj->rowid.' lastname='.$obj->lastname.' firstname='.$obj->firstname.' photo='.$obj->photo.' file '.$filetotest." exists=".$exists."<br>\n";
763 if ($exists) {
764 $filetarget = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/'.$name.$ext;
765 $filetargetsmall = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_small'.$ext;
766 $filetargetmini = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_mini'.$ext;
767
768 $existt = dol_is_file($filetarget);
769 if (!$existt) {
770 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
771 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid);
772 }
773
774 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
775 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
776 dol_copy($filetotest, $filetarget, '', 0);
777 }
778 }
779
780 $existtt = dol_is_file($filetargetsmall);
781 if (!$existtt) {
782 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
783 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
784 }
785
786 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
787 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
788 dol_copy($filetotestsmall, $filetargetsmall, '', 0);
789 }
790 }
791
792 $existtt = dol_is_file($filetargetmini);
793 if (!$existtt) {
794 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
795 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
796 }
797
798 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestmini." -> ".$filetargetmini."<br>\n";
799 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
800 dol_copy($filetotestmini, $filetargetmini, '', 0);
801 }
802 }
803 }
804 }
805
806 $i++;
807 }
808 } else {
809 $ok = 0;
810 dol_print_error($db);
811 }
812
813 print '</td></tr>';
814}
815
816
817// rebuild_product_thumbs: Rebuild thumbs for product files
818if ($ok && GETPOST('rebuild_product_thumbs', 'alpha')) {
819 $ext = '';
820 global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
821
822 print '<tr><td colspan="2"><br>*** Rebuild product thumbs<br>';
823
824 $sql = "SELECT s.rowid, s.ref FROM ".MAIN_DB_PREFIX."product as s ORDER BY s.ref";
825 $resql = $db->query($sql);
826 if ($resql) {
827 $num = $db->num_rows($resql);
828 $i = 0;
829
830 while ($i < $num) {
831 $obj = $db->fetch_object($resql);
832
833 if (!empty($obj->ref)) {
834 $files = dol_dir_list($dolibarr_main_data_root.'/produit/'.$obj->ref, 'files', 0);
835 foreach ($files as $file) {
836 // Generate thumbs.
837 if (image_format_supported($file['fullname']) == 1) {
838 $imgThumbSmall = 'notbuild';
839 if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
840 // Used on logon for example
841 $imgThumbSmall = vignette($file['fullname'], $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
842 }
843 print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbSmall." maxwidthsmall=".$maxwidthsmall." maxheightsmall=".$maxheightsmall."<br>\n";
844 $imgThumbMini = 'notbuild';
845 if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
846 // Create mini thumbs for image (Ratio is near 16/9)
847 // Used on menu or for setup page for example
848 $imgThumbMini = vignette($file['fullname'], $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
849 }
850 print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbMini." maxwidthmini=".$maxwidthmini." maxheightmini=".$maxheightmini."<br>\n";
851 }
852 }
853 }
854
855 $i++;
856 }
857 } else {
858 $ok = 0;
859 dol_print_error($db);
860 }
861
862 print '</td></tr>';
863}
864
865// clean_linked_elements: Check and clean linked elements
866if ($ok && GETPOST('clean_linked_elements', 'alpha')) {
867 print '<tr><td colspan="2"><br>*** Check table of linked elements and delete orphelins links</td></tr>';
868 // propal => order
869 print '<tr><td colspan="2">'.checkLinkedElements('propal', 'commande')."</td></tr>\n";
870
871 // propal => invoice
872 print '<tr><td colspan="2">'.checkLinkedElements('propal', 'facture')."</td></tr>\n";
873
874 // order => invoice
875 print '<tr><td colspan="2">'.checkLinkedElements('commande', 'facture')."</td></tr>\n";
876
877 // order => shipping
878 print '<tr><td colspan="2">'.checkLinkedElements('commande', 'shipping')."</td></tr>\n";
879
880 // shipping => delivery
881 print '<tr><td colspan="2">'.checkLinkedElements('shipping', 'delivery')."</td></tr>\n";
882
883 // order_supplier => invoice_supplier
884 print '<tr><td colspan="2">'.checkLinkedElements('order_supplier', 'invoice_supplier')."</td></tr>\n";
885}
886
887
888// clean_menus: Check orphelins menus
889if ($ok && GETPOST('clean_menus', 'alpha')) {
890 print '<tr><td colspan="2"><br>*** Clean menu entries coming from disabled modules</td></tr>';
891
892 $sql = "SELECT rowid, module";
893 $sql .= " FROM ".MAIN_DB_PREFIX."menu as c";
894 $sql .= " WHERE module IS NOT NULL AND module <> ''";
895 $sql .= " ORDER BY module";
896
897 $resql = $db->query($sql);
898 if ($resql) {
899 $num = $db->num_rows($resql);
900 if ($num) {
901 $i = 0;
902 while ($i < $num) {
903 $obj = $db->fetch_object($resql);
904
905 $modulecond = $obj->module;
906 $modulecondarray = explode('|', $obj->module); // Name of module
907
908 print '<tr><td>';
909 print $modulecond;
910
911 $db->begin();
912
913 if ($modulecond) { // And menu entry for module $modulecond was found in database.
914 $moduleok = 0;
915 foreach ($modulecondarray as $tmpname) {
916 if ($tmpname == 'margins') {
917 $tmpname = 'margin'; // TODO Remove this when normalized
918 }
919
920 $result = 0;
921 if (!empty($conf->$tmpname)) {
922 $result = $conf->$tmpname->enabled;
923 }
924 if ($result) {
925 $moduleok++;
926 }
927 }
928
929 if (!$moduleok && $modulecond) {
930 print ' - Module condition '.$modulecond.' seems ko, we delete menu entry.';
931 if (GETPOST('clean_menus') == 'confirmed') {
932 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."menu WHERE module = '".$db->escape($modulecond)."'";
933 $resql2 = $db->query($sql2);
934 if (!$resql2) {
935 $error++;
936 dol_print_error($db);
937 } else {
938 print ' - <span class="warning">Cleaned</span>';
939 }
940 } else {
941 print ' - <span class="warning">Canceled (test mode)</span>';
942 }
943 } else {
944 print ' - Module condition '.$modulecond.' is ok, we do nothing.';
945 }
946 }
947
948 if (!$error) {
949 $db->commit();
950 } else {
951 $db->rollback();
952 }
953
954 print'</td></tr>';
955
956 if ($error) {
957 break;
958 }
959
960 $i++;
961 }
962 } else {
963 print '<tr><td>No menu entries of disabled menus found</td></tr>';
964 }
965 } else {
966 dol_print_error($db);
967 }
968}
969
970
971
972// clean_orphelin_dir: Run purge of directory
973if ($ok && GETPOST('clean_orphelin_dir', 'alpha')) {
974 $listmodulepart = array('company', 'invoice', 'invoice_supplier', 'propal', 'order', 'order_supplier', 'contract', 'tax');
975 foreach ($listmodulepart as $modulepart) {
976 $filearray = array();
977 $upload_dir = isset($conf->$modulepart->dir_output) ? $conf->$modulepart->dir_output : '';
978 if ($modulepart == 'company') {
979 $upload_dir = $conf->societe->dir_output; // TODO change for multicompany sharing
980 }
981 if ($modulepart == 'invoice') {
982 $upload_dir = $conf->facture->dir_output;
983 }
984 if ($modulepart == 'invoice_supplier') {
985 $upload_dir = $conf->fournisseur->facture->dir_output;
986 }
987 if ($modulepart == 'order') {
988 $upload_dir = $conf->commande->dir_output;
989 }
990 if ($modulepart == 'order_supplier') {
991 $upload_dir = $conf->fournisseur->commande->dir_output;
992 }
993 if ($modulepart == 'contract') {
994 $upload_dir = $conf->contrat->dir_output;
995 }
996
997 if (empty($upload_dir)) {
998 continue;
999 }
1000
1001 print '<tr><td colspan="2"><br>*** Clean orphelins files into files '.$upload_dir.'</td></tr>';
1002
1003 $filearray = dol_dir_list($upload_dir, "files", 1, '', array('^SPECIMEN\.pdf$', '^\.', '(\.meta|_preview.*\.png)$', '^temp$', '^payments$', '^CVS$', '^thumbs$'), '', SORT_DESC, 1, 1);
1004
1005 $object_instance = null;
1006 // To show ref or specific information according to view to show (defined by $module)
1007 if ($modulepart == 'company') {
1008 include_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1009 $object_instance = new Societe($db);
1010 }
1011 if ($modulepart == 'invoice') {
1012 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
1013 $object_instance = new Facture($db);
1014 } elseif ($modulepart == 'invoice_supplier') {
1015 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
1016 $object_instance = new FactureFournisseur($db);
1017 } elseif ($modulepart == 'propal') {
1018 include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
1019 $object_instance = new Propal($db);
1020 } elseif ($modulepart == 'order') {
1021 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
1022 $object_instance = new Commande($db);
1023 } elseif ($modulepart == 'order_supplier') {
1024 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
1025 $object_instance = new CommandeFournisseur($db);
1026 } elseif ($modulepart == 'contract') {
1027 include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
1028 $object_instance = new Contrat($db);
1029 } elseif ($modulepart == 'tax') {
1030 include_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php';
1031 $object_instance = new ChargeSociales($db);
1032 }
1033
1034 foreach ($filearray as $key => $file) {
1035 if (!is_dir($file['name'])
1036 && $file['name'] != '.'
1037 && $file['name'] != '..'
1038 && $file['name'] != 'CVS'
1039 ) {
1040 // Define relative path used to store the file
1041 $relativefile = preg_replace('/'.preg_quote($upload_dir.'/', '/').'/', '', $file['fullname']);
1042
1043 //var_dump($file);
1044 $id = 0;
1045 $ref = '';
1046 $object_instance->id = 0;
1047 $object_instance->ref = '';
1048 $label = '';
1049
1050 // To show ref or specific information according to view to show (defined by $module)
1051 if ($modulepart == 'invoice') {
1052 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
1053 $ref = empty($reg[1]) ? '' : $reg[1];
1054 }
1055 if ($modulepart == 'invoice_supplier') {
1056 preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg);
1057 $id = empty($reg[1]) ? '' : $reg[1];
1058 }
1059 if ($modulepart == 'propal') {
1060 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
1061 $ref = empty($reg[1]) ? '' : $reg[1];
1062 }
1063 if ($modulepart == 'order') {
1064 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
1065 $ref = empty($reg[1]) ? '' : $reg[1];
1066 }
1067 if ($modulepart == 'order_supplier') {
1068 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
1069 $ref = empty($reg[1]) ? '' : $reg[1];
1070 }
1071 if ($modulepart == 'contract') {
1072 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
1073 $ref = empty($reg[1]) ? '' : $reg[1];
1074 }
1075 if ($modulepart == 'tax') {
1076 preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg);
1077 $id = $reg[1];
1078 }
1079
1080 if (($id || $ref) && $object_instance !== null) {
1081 //print 'Fetch '.$id.' or '.$ref.'<br>';
1082 $result = $object_instance->fetch($id, $ref);
1083 //print $result.'<br>';
1084 if ($result == 0) { // Not found but no error
1085 // Clean of orphelins directories are done into repair.php
1086 print '<tr><td colspan="2">';
1087 print 'Delete orphelins file '.$file['fullname'].'<br>';
1088 if (GETPOST('clean_orphelin_dir', 'alpha') == 'confirmed') {
1089 dol_delete_file($file['fullname'], 1, 1, 1);
1090 dol_delete_dir(dirname($file['fullname']), 1);
1091 }
1092 print "</td></tr>";
1093 } elseif ($result < 0) {
1094 print 'Error in '.get_class($object_instance).'.fetch of id'.$id.' ref='.$ref.', result='.$result.'<br>';
1095 }
1096 }
1097 }
1098 }
1099 }
1100}
1101
1102$methodtofix = '';
1103// clean_linked_elements: Check and clean linked elements
1104if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) {
1105 $methodtofix = GETPOST('methodtofix', 'alpha') ? GETPOST('methodtofix', 'alpha') : 'updatestock';
1106
1107 print '<tr><td colspan="2"><br>*** Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
1108
1109 $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
1110 $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";
1111 $sql .= " WHERE p.rowid = ps.fk_product";
1112 $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
1113 $sql .= " HAVING (SUM(pb.qty) IS NOT NULL AND reel != SUM(pb.qty)) OR (SUM(pb.qty) IS NULL AND p.tobatch > 0)";
1114
1115 $resql = $db->query($sql);
1116 if ($resql) {
1117 $num = $db->num_rows($resql);
1118
1119 if ($num) {
1120 $i = 0;
1121 while ($i < $num) {
1122 $obj = $db->fetch_object($resql);
1123 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)';
1124
1125 // Fix is required
1126 if ($obj->reel != $obj->reelbatch) {
1127 if (empty($obj->tobatch)) {
1128 // If product is not a product that support batches, we can clean stock by deleting the product batch lines
1129 print ' -> Delete qty '.$obj->reelbatch.' for any lot linked to fk_product_stock='.$obj->psrowid;
1130 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."product_batch";
1131 $sql2 .= " WHERE fk_product_stock = ".((int) $obj->psrowid);
1132 print '<br>'.$sql2;
1133
1134 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
1135 $resql2 = $db->query($sql2);
1136 if (!$resql2) {
1137 $error++;
1138 dol_print_error($db);
1139 }
1140 }
1141 } else {
1142 if ($methodtofix == 'updatebatch') {
1143 // Method 1
1144 print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid;
1145 $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)";
1146 $sql2 .= "VALUES(".((int) $obj->psrowid).", '000000', ".((float) ($obj->reel - $obj->reelbatch)).")";
1147 print '<br>'.$sql2;
1148
1149 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
1150 $resql2 = $db->query($sql2);
1151 if (!$resql2) {
1152 // TODO If it fails, we must make update
1153 //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch";
1154 //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")";
1155 //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid)
1156 }
1157 }
1158 }
1159 if ($methodtofix == 'updatestock') {
1160 // Method 2
1161 print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid);
1162 $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock";
1163 $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid);
1164 print '<br>'.$sql2;
1165
1166 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
1167 $error = 0;
1168
1169 $db->begin();
1170
1171 $resql2 = $db->query($sql2);
1172 if ($resql2) {
1173 // We update product_stock, so we must fill p.stock into product too.
1174 $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)';
1175 $resql3 = $db->query($sql3);
1176 if (!$resql3) {
1177 $error++;
1178 dol_print_error($db);
1179 }
1180 } else {
1181 $error++;
1182 dol_print_error($db);
1183 }
1184
1185 if (!$error) {
1186 $db->commit();
1187 } else {
1188 $db->rollback();
1189 }
1190 }
1191 }
1192 }
1193 }
1194
1195 print'</td></tr>';
1196
1197 $i++;
1198 }
1199 } else {
1200 print '<tr><td colspan="2">Nothing to do</td></tr>';
1201 }
1202 } else {
1203 dol_print_error($db);
1204 }
1205}
1206
1207
1208// clean_product_stock_negative_if_batch
1209if ($ok && GETPOST('clean_product_stock_negative_if_batch', 'alpha')) {
1210 print '<tr><td colspan="2"><br>Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
1211
1212 $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
1213 $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product_batch as pb";
1214 $sql .= " WHERE p.rowid = ps.fk_product AND ps.rowid = pb.fk_product_stock";
1215 $sql .= " AND p.tobatch > 0";
1216 $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
1217 $sql .= " HAVING reel != SUM(pb.qty)";
1218 $resql = $db->query($sql);
1219 if ($resql) {
1220 $num = $db->num_rows($resql);
1221
1222 if ($num) {
1223 $i = 0;
1224 while ($i < $num) {
1225 $obj = $db->fetch_object($resql);
1226 print '<tr><td>'.$obj->rowid.'-'.$obj->ref.'-'.$obj->fk_entrepot.' -> '.$obj->psrowid.': '.$obj->reel.' != '.$obj->reelbatch;
1227
1228 // TODO
1229 }
1230 }
1231 }
1232}
1233
1234// set_empty_time_spent_amount
1235if ($ok && GETPOST('set_empty_time_spent_amount', 'alpha')) {
1236 print '<tr><td colspan="2"><br>*** Set value of time spent without amount</td></tr>';
1237
1238 $sql = "SELECT COUNT(ptt.rowid) as nb, u.rowid as user_id, u.login, u.thm as user_thm";
1239 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."user as u";
1240 $sql .= " WHERE ptt.fk_user = u.rowid";
1241 $sql .= " AND ptt.thm IS NULL and u.thm > 0";
1242 $sql .= " GROUP BY u.rowid, u.login, u.thm";
1243
1244 $resql = $db->query($sql);
1245 if ($resql) {
1246 $num = $db->num_rows($resql);
1247
1248 if ($num) {
1249 $i = 0;
1250 while ($i < $num) {
1251 $obj = $db->fetch_object($resql);
1252 print '<tr><td>'.$obj->login.'-'.$obj->user_id.' ('.$obj->nb.' lines to fix) -> '.$obj->user_thm;
1253
1254 $db->begin();
1255
1256 if (GETPOST('set_empty_time_spent_amount') == 'confirmed') {
1257 $sql2 = "UPDATE ".MAIN_DB_PREFIX."element_time";
1258 $sql2 .= " SET thm = ".$obj->user_thm." WHERE thm IS NULL AND fk_user = ".((int) $obj->user_id);
1259 $resql2 = $db->query($sql2);
1260 if (!$resql2) {
1261 $error++;
1262 dol_print_error($db);
1263 }
1264 }
1265
1266 if (!$error) {
1267 $db->commit();
1268 } else {
1269 $db->rollback();
1270 }
1271
1272 print'</td></tr>';
1273
1274 if ($error) {
1275 break;
1276 }
1277
1278 $i++;
1279 }
1280 } else {
1281 print '<tr><td>No time spent with empty line on users with a hourly rate defined</td></tr>';
1282 }
1283 } else {
1284 dol_print_error($db);
1285 }
1286}
1287
1288
1289// force_disable_of_modules_not_found
1290if ($ok && GETPOST('force_disable_of_modules_not_found', 'alpha')) {
1291 print '<tr><td colspan="2"><br>*** Force modules not found physically to be disabled (only modules adding js, css or hooks can be detected as removed physically)</td></tr>';
1292
1293 $arraylistofkey = array('hooks', 'js', 'css');
1294
1295 foreach ($arraylistofkey as $key) {
1296 $sql = "SELECT DISTINCT name, value";
1297 $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
1298 $sql .= " WHERE name LIKE 'MAIN_MODULE_%_".strtoupper($db->escape($key))."'";
1299 $sql .= " ORDER BY name";
1300
1301 $resql = $db->query($sql);
1302 if ($resql) {
1303 $num = $db->num_rows($resql);
1304 if ($num) {
1305 $i = 0;
1306 while ($i < $num) {
1307 $obj = $db->fetch_object($resql);
1308 $constantname = $obj->name; // Name of constant for hook or js or css declaration
1309
1310 print '<tr><td>';
1311 print dol_escape_htmltag($constantname);
1312
1313 $db->begin();
1314
1315 $reg = array();
1316 if (preg_match('/MAIN_MODULE_(.*)_'.strtoupper($key).'/i', $constantname, $reg)) {
1317 $name = strtolower($reg[1]);
1318
1319 if ($name) { // An entry for key $key and module $name was found in database.
1320 $reloffile = '';
1321 $result = 'found';
1322
1323 if ($key == 'hooks') {
1324 $reloffile = $name.'/class/actions_'.$name.'.class.php';
1325 }
1326 if ($key == 'js') {
1327 $value = $obj->value;
1328 $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1329 $reloffile = $valuearray[0];
1330 $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1331 }
1332 if ($key == 'css') {
1333 $value = $obj->value;
1334 $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1335 if ($value && (!is_array($valuearray) || count($valuearray) == 0)) {
1336 $valuearray = array();
1337 $valuearray[0] = $value; // If value was not a json array but a string
1338 }
1339 $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1340 }
1341
1342 if ($reloffile) {
1343 //var_dump($key.' - '.$value.' - '.$reloffile);
1344 try {
1345 $result = dol_buildpath($reloffile, 0, 2);
1346 } catch (Exception $e) {
1347 $result = 'found'; // If error, we force like if we found to avoid any deletion
1348 }
1349 } else {
1350 $result = 'found'; //
1351 }
1352
1353 if (!$result) {
1354 print ' - File of '.$key.' ('.$reloffile.') NOT found, we disable the module.';
1355 if (GETPOST('force_disable_of_modules_not_found') == 'confirmed') {
1356 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."_".strtoupper($key)."'";
1357 $resql2 = $db->query($sql2);
1358 if (!$resql2) {
1359 $error++;
1360 dol_print_error($db);
1361 }
1362 $sql3 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."'";
1363 $resql3 = $db->query($sql3);
1364 if (!$resql3) {
1365 $error++;
1366 dol_print_error($db);
1367 } else {
1368 print ' - <span class="warning">Cleaned</span>';
1369 }
1370 } else {
1371 print ' - <span class="warning">Canceled (test mode)</span>';
1372 }
1373 } else {
1374 print ' - File of '.$key.' ('.$reloffile.') found, we do nothing.';
1375 }
1376 }
1377
1378 if (!$error) {
1379 $db->commit();
1380 } else {
1381 $db->rollback();
1382 }
1383 }
1384
1385 print'</td></tr>';
1386
1387 if ($error) {
1388 break;
1389 }
1390
1391 $i++;
1392 }
1393 } else {
1394 print '<tr><td>No active module with missing files found by searching on MAIN_MODULE_(.*)_'.strtoupper($key).'</td></tr>';
1395 }
1396 } else {
1397 dol_print_error($db);
1398 }
1399 }
1400}
1401
1402
1403// clean_old_module_entries: Clean data into const when files of module were removed without being
1404if ($ok && GETPOST('clean_perm_table', 'alpha')) {
1405 print '<tr><td colspan="2"><br>*** Clean table user_rights from lines of external modules no more enabled</td></tr>';
1406
1407 $listofmods = '';
1408 foreach ($conf->modules as $key => $val) {
1409 $listofmods .= ($listofmods ? ',' : '')."'".$db->escape($val)."'";
1410 }
1411
1412 $sql = "SELECT id, libelle as label, module from ".MAIN_DB_PREFIX."rights_def WHERE module NOT IN (".$db->sanitize($listofmods, 1).") AND id > 100000";
1413
1414 $resql = $db->query($sql);
1415 if ($resql) {
1416 $num = $db->num_rows($resql);
1417 if ($num) {
1418 $i = 0;
1419 while ($i < $num) {
1420 $obj = $db->fetch_object($resql);
1421 if ($obj->id > 0) {
1422 print '<tr><td>Found line with id '.$obj->id.', label "'.$obj->label.'" of module "'.$obj->module.'" to delete';
1423 if (GETPOST('clean_perm_table', 'alpha') == 'confirmed') {
1424 $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."rights_def WHERE id = ".((int) $obj->id);
1425 $resqldelete = $db->query($sqldelete);
1426 if (!$resqldelete) {
1427 dol_print_error($db);
1428 }
1429 print ' - deleted';
1430 }
1431 print '</td></tr>';
1432 }
1433 $i++;
1434 }
1435 } else {
1436 print '<tr><td>No lines of a disabled external module (with id > 100000) found into table rights_def</td></tr>';
1437 }
1438 } else {
1439 dol_print_error($db);
1440 }
1441}
1442
1443
1444// clean_old_module_entries: Clean data into const when files of module were removed without being
1445if ($ok && GETPOST('clean_ecm_files_table', 'alpha')) {
1446 print '<tr><td colspan="2"><br>*** Clean table ecm_files from lines of entries whose physical files does not exists anymore (emplemented for entity 1 only)</td></tr>';
1447
1448 $MAXTODELETE = 100;
1449
1450 $sql = "SELECT rowid, filename, filepath, entity from ".MAIN_DB_PREFIX."ecm_files";
1451 $sql .= " WHERE entity = 1";
1452 $sql .= " ORDER BY rowid ASC";
1453
1454 $nbfile = 0;
1455 $nbfiletodelete = 0;
1456
1457 $resql = $db->query($sql);
1458 if ($resql) {
1459 $num = $db->num_rows($resql);
1460 if ($num) {
1461 $i = 0;
1462 while ($i < $num) {
1463 $obj = $db->fetch_object($resql);
1464 if ($obj->rowid > 0) {
1465 $filetocheck = DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename;
1466 $nbfile++;
1467 if (!dol_is_file($filetocheck) && !dol_is_file($filetocheck.'.noexe')) {
1468 $nbfiletodelete++;
1469 if ($nbfiletodelete <= $MAXTODELETE) {
1470 print '<tr><td>Found line with id '.$obj->rowid.', entity '.$obj->entity.', file "'.$filetocheck.'" to delete';
1471 if (GETPOST('clean_ecm_files_table', 'alpha') == 'confirmed') {
1472 $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."ecm_files WHERE rowid = ".((int) $obj->rowid);
1473 $resqldelete = $db->query($sqldelete);
1474 if (!$resqldelete) {
1475 dol_print_error($db);
1476 }
1477 print ' - deleted';
1478 }
1479 print '</td></tr>';
1480 } else {
1481 break;
1482 }
1483 }
1484 }
1485 $i++;
1486 }
1487 }
1488 if ($nbfiletodelete > $MAXTODELETE) {
1489 print '<tr><td>There is more than '.$MAXTODELETE.' invalid entries into ecm_files index table (among '.$nbfile.' analyzed) with no valid physical files. Run the page several time to process all of them.</td></tr>';
1490 } else {
1491 print '<tr><td>Nb of entries processed into ecm_files index table: '.$nbfile.', number of invalid record: '.$nbfiletodelete.'</td></tr>';
1492 }
1493 } else {
1494 dol_print_error($db);
1495 }
1496}
1497
1498// force utf8 on tables
1499if ($ok && GETPOST('force_utf8_on_tables', 'alpha')) {
1500 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>';
1501
1502 if ($db->type == "mysql" || $db->type == "mysqli") {
1503 $force_utf8_on_tables = GETPOST('force_utf8_on_tables', 'alpha');
1504
1505 $listoftables = $db->DDLListTablesFull($db->database_name);
1506
1507 // Disable foreign key checking for avoid errors
1508 if ($force_utf8_on_tables == 'confirmed') {
1509 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1510 print '<!-- '.$sql.' -->';
1511 print '<tr><td colspan="2">'.$sql.'</td></tr>';
1512 $resql = $db->query($sql);
1513 }
1514
1515 $foreignkeystorestore = array();
1516
1517 // First loop to delete foreign keys
1518 foreach ($listoftables as $table) {
1519 // do not convert llx_const if mysql encrypt/decrypt is used
1520 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1521 continue;
1522 }
1523 if ($table[1] == 'VIEW') {
1524 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' <span class="opacitymedium">(Skipped)</span></td></tr>';
1525 continue;
1526 }
1527
1528 // Special case of tables with foreign key on varchar fields
1529 $arrayofforeignkey = array(
1530 'llx_accounting_account' => 'fk_accounting_account_fk_pcg_version',
1531 'llx_accounting_system' => 'fk_accounting_account_fk_pcg_version',
1532 'llx_c_type_contact' => 'fk_societe_commerciaux_fk_c_type_contact_code',
1533 'llx_societe_commerciaux' => 'fk_societe_commerciaux_fk_c_type_contact_code'
1534 );
1535
1536 foreach ($arrayofforeignkey as $tmptable => $foreignkeyname) {
1537 if ($table[0] == $tmptable) {
1538 print '<tr><td colspan="2">';
1539 $sqltmp = "ALTER TABLE ".$db->sanitize($table[0])." DROP FOREIGN KEY ".$db->sanitize($foreignkeyname);
1540 print $sqltmp;
1541 if ($force_utf8_on_tables == 'confirmed') {
1542 $resqltmp = $db->query($sqltmp);
1543 } else {
1544 print ' - <span class="opacitymedium">Disabled</span>';
1545 }
1546 print '</td></tr>';
1547 $foreignkeystorestore[$tmptable] = $foreignkeyname;
1548 }
1549 }
1550 }
1551
1552 foreach ($listoftables as $table) {
1553 // do not convert llx_const if mysql encrypt/decrypt is used
1554 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1555 continue;
1556 }
1557 if ($table[1] == 'VIEW') {
1558 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' <span class="opacitymedium">(Skipped)</span></td></tr>';
1559 continue;
1560 }
1561
1562 $collation = 'utf8_unicode_ci';
1563 $defaultcollation = $db->getDefaultCollationDatabase();
1564 if (preg_match('/general/', $defaultcollation)) {
1565 $collation = 'utf8_general_ci';
1566 }
1567
1568 print '<tr><td colspan="2">';
1569 print $table[0];
1570 $sql1 = "ALTER TABLE ".$db->sanitize($table[0])." ROW_FORMAT=dynamic";
1571 $sql2 = "ALTER TABLE ".$db->sanitize($table[0])." CONVERT TO CHARACTER SET utf8 COLLATE ".$db->sanitize($collation);
1572 print '<!-- '.$sql1.' -->';
1573 print '<!-- '.$sql2.' -->';
1574 if ($force_utf8_on_tables == 'confirmed') {
1575 $resql1 = $db->query($sql1);
1576 if ($resql1) {
1577 $resql2 = $db->query($sql2);
1578 } else {
1579 $resql2 = false;
1580 }
1581 print ' - Done '.(($resql1 && $resql2) ? '<span class="opacitymedium">(OK)</span>' : '<span class="error" title="'.dol_escape_htmltag($db->lasterror).'">(KO)</span>');
1582 } else {
1583 print ' - <span class="opacitymedium">Disabled</span>';
1584 }
1585 print '</td></tr>';
1586 flush();
1587 if (ob_get_level() > 0) {
1588 ob_flush();
1589 }
1590 }
1591
1592 // Restore dropped foreign keys
1593 foreach ($foreignkeystorestore as $tmptable => $foreignkeyname) {
1594 $stringtofindinline = "ALTER TABLE .* ADD CONSTRAINT ".$db->sanitize($foreignkeyname);
1595 $fileforkeys = DOL_DOCUMENT_ROOT.'/install/mysql/tables/'.$tmptable.'.key.sql';
1596 //print 'Search in '.$fileforkeys.' to get '.$stringtofindinline."<br>\n";
1597
1598 $handle = fopen($fileforkeys, 'r');
1599 if ($handle) {
1600 while (($line = fgets($handle)) !== false) {
1601 // Process the line read.
1602 if (preg_match('/^'.$stringtofindinline.'/i', $line)) {
1603 $resqltmp = $db->query($line);
1604 print '<tr><td colspan="2">';
1605 print $line;
1606 print ' - Done '.($resqltmp ? '<span class="opacitymedium">(OK)</span>' : '<span class="error" title="'.dol_escape_htmltag($db->lasterror).'">(KO)</span>');
1607 print '</td></tr>';
1608 break;
1609 }
1610 }
1611 fclose($handle);
1612 }
1613 flush();
1614 if (ob_get_level() > 0) {
1615 ob_flush();
1616 }
1617 }
1618
1619 // Enable foreign key checking
1620 if ($force_utf8_on_tables == 'confirmed') {
1621 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1622 print '<!-- '.$sql.' -->';
1623 print '<tr><td colspan="2">'.$sql.'</td></tr>';
1624 $resql = $db->query($sql);
1625 }
1626 } else {
1627 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1628 }
1629}
1630
1631// force utf8mb4 on tables EXPERIMENTAL !
1632if ($ok && GETPOST('force_utf8mb4_on_tables', 'alpha')) {
1633 print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8mb4/utf8mb4_unicode_ci (for mysql/mariadb only)</td></tr>';
1634
1635 if ($db->type == "mysql" || $db->type == "mysqli") {
1636 $force_utf8mb4_on_tables = GETPOST('force_utf8mb4_on_tables', 'alpha');
1637
1638
1639 $listoftables = $db->DDLListTablesFull($db->database_name);
1640
1641 // Disable foreign key checking for avoid errors
1642 if ($force_utf8mb4_on_tables == 'confirmed') {
1643 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1644 print '<!-- '.$sql.' -->';
1645 print '<tr><td colspan="2">'.$sql.'</td></tr>';
1646 $resql = $db->query($sql);
1647 }
1648
1649 $foreignkeystorestore = array();
1650
1651 // First loop to delete foreign keys
1652 foreach ($listoftables as $table) {
1653 // do not convert llx_const if mysql encrypt/decrypt is used
1654 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1655 continue;
1656 }
1657 if ($table[1] == 'VIEW') {
1658 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' <span class="opacitymedium">(Skipped)</span></td></tr>';
1659 continue;
1660 }
1661
1662 // Special case of tables with foreign key on varchar fields
1663 $arrayofforeignkey = array(
1664 'llx_accounting_account' => 'fk_accounting_account_fk_pcg_version',
1665 'llx_accounting_system' => 'fk_accounting_account_fk_pcg_version',
1666 'llx_c_type_contact' => 'fk_societe_commerciaux_fk_c_type_contact_code',
1667 'llx_societe_commerciaux' => 'fk_societe_commerciaux_fk_c_type_contact_code'
1668 );
1669
1670 foreach ($arrayofforeignkey as $tmptable => $foreignkeyname) {
1671 if ($table[0] == $tmptable) {
1672 print '<tr><td colspan="2">';
1673 $sqltmp = "ALTER TABLE ".$db->sanitize($table[0])." DROP FOREIGN KEY ".$db->sanitize($foreignkeyname);
1674 print $sqltmp;
1675 if ($force_utf8mb4_on_tables == 'confirmed') {
1676 $resqltmp = $db->query($sqltmp);
1677 } else {
1678 print ' - <span class="opacitymedium">Disabled</span>';
1679 }
1680 print '</td></tr>';
1681 $foreignkeystorestore[$tmptable] = $foreignkeyname;
1682 }
1683 }
1684 }
1685
1686 foreach ($listoftables as $table) {
1687 // do not convert llx_const if mysql encrypt/decrypt is used
1688 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1689 continue;
1690 }
1691 if ($table[1] == 'VIEW') {
1692 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' <span class="opacitymedium">(Skipped)</span></td></tr>';
1693 continue;
1694 }
1695
1696 $collation = 'utf8mb4_unicode_ci';
1697 $defaultcollation = $db->getDefaultCollationDatabase();
1698 if (preg_match('/general/', $defaultcollation)) {
1699 $collation = 'utf8mb4_general_ci';
1700 }
1701
1702 print '<tr><td colspan="2">';
1703 print $table[0];
1704 $sql1 = "ALTER TABLE ".$db->sanitize($table[0])." ROW_FORMAT=dynamic";
1705 $sql2 = "ALTER TABLE ".$db->sanitize($table[0])." CONVERT TO CHARACTER SET utf8mb4 COLLATE ".$db->sanitize($collation);
1706 print '<!-- '.$sql1.' -->';
1707 print '<!-- '.$sql2.' -->';
1708 if ($force_utf8mb4_on_tables == 'confirmed') {
1709 $resql1 = $db->query($sql1);
1710 if ($resql1) {
1711 $resql2 = $db->query($sql2);
1712 } else {
1713 $resql2 = false;
1714 }
1715 print ' - Done '.(($resql1 && $resql2) ? '<span class="opacitymedium">(OK)</span>' : '<span class="error" title="'.dol_escape_htmltag($db->lasterror).'">(KO)</span>');
1716 } else {
1717 print ' - <span class="opacitymedium">Disabled</span>';
1718 }
1719 print '</td></tr>';
1720 flush();
1721 if (ob_get_level() > 0) {
1722 ob_flush();
1723 }
1724 }
1725
1726 // Restore dropped foreign keys
1727 foreach ($foreignkeystorestore as $tmptable => $foreignkeyname) {
1728 $stringtofindinline = "ALTER TABLE .* ADD CONSTRAINT ".$db->sanitize($foreignkeyname);
1729 $fileforkeys = DOL_DOCUMENT_ROOT.'/install/mysql/tables/'.$tmptable.'.key.sql';
1730 //print 'Search in '.$fileforkeys.' to get '.$stringtofindinline."<br>\n";
1731
1732 $handle = fopen($fileforkeys, 'r');
1733 if ($handle) {
1734 while (($line = fgets($handle)) !== false) {
1735 // Process the line read.
1736 if (preg_match('/^'.$stringtofindinline.'/i', $line)) {
1737 $resqltmp = $db->query($line);
1738 print '<tr><td colspan="2">';
1739 print $line;
1740 print ' - Done '.($resqltmp ? '<span class="opacitymedium">(OK)</span>' : '<span class="error" title="'.dol_escape_htmltag($db->lasterror).'">(KO)</span>');
1741 print '</td></tr>';
1742 break;
1743 }
1744 }
1745 fclose($handle);
1746 }
1747 flush();
1748 if (ob_get_level() > 0) {
1749 ob_flush();
1750 }
1751 }
1752
1753 // Enable foreign key checking
1754 if ($force_utf8mb4_on_tables == 'confirmed') {
1755 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1756 print '<!-- '.$sql.' -->';
1757 print '<tr><td colspan="2">'.$sql.'</td></tr>';
1758 $resql = $db->query($sql);
1759 }
1760 } else {
1761 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1762 }
1763}
1764
1765if ($ok && GETPOST('force_collation_from_conf_on_tables', 'alpha')) {
1766 print '<tr><td colspan="2"><br>*** Force page code and collation of tables into '.$conf->db->character_set.'/'.$conf->db->dolibarr_main_db_collation.' and row_format=dynamic (for mysql/mariadb only)</td></tr>';
1767
1768 if ($db->type == "mysql" || $db->type == "mysqli") {
1769 $force_collation_from_conf_on_tables = GETPOST('force_collation_from_conf_on_tables', 'alpha');
1770
1771 $listoftables = $db->DDLListTablesFull($db->database_name);
1772
1773 // Disable foreign key checking for avoid errors
1774 if ($force_collation_from_conf_on_tables == 'confirmed') {
1775 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1776 print '<!-- '.$sql.' -->';
1777 $resql = $db->query($sql);
1778 }
1779
1780 foreach ($listoftables as $table) {
1781 // do not convert collation on llx_const if mysql encrypt/decrypt is used
1782 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1783 continue;
1784 }
1785 if ($table[1] == 'VIEW') {
1786 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1787 continue;
1788 }
1789
1790 print '<tr><td colspan="2">';
1791 print $table[0];
1792 $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1793 $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET ".$conf->db->character_set." COLLATE ".$conf->db->dolibarr_main_db_collation;
1794 print '<!-- '.$sql1.' -->';
1795 print '<!-- '.$sql2.' -->';
1796 if ($force_collation_from_conf_on_tables == 'confirmed') {
1797 $resql1 = $db->query($sql1);
1798 if ($resql1) {
1799 $resql2 = $db->query($sql2);
1800 } else {
1801 $resql2 = false;
1802 }
1803 print ' - Done '.(($resql1 && $resql2) ? '<span class="opacitymedium">(OK)</span>' : '<span class="error" title="'.dol_escape_htmltag($db->lasterror).'">(KO)</span>');
1804 } else {
1805 print ' - <span class="opacitymedium">Disabled</span>';
1806 }
1807 print '</td></tr>';
1808 }
1809
1810 // Enable foreign key checking
1811 if ($force_collation_from_conf_on_tables == 'confirmed') {
1812 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1813 print '<!-- '.$sql.' -->';
1814 $resql = $db->query($sql);
1815 }
1816 } else {
1817 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1818 }
1819}
1820
1821// rebuild sequences for pgsql
1822if ($ok && GETPOST('rebuild_sequences', 'alpha')) {
1823 print '<tr><td colspan="2"><br>*** Force to rebuild sequences (for postgresql only)</td></tr>';
1824
1825 if ($db->type == "pgsql") {
1826 $rebuild_sequence = GETPOST('rebuild_sequences', 'alpha');
1827
1828 if ($rebuild_sequence == 'confirmed') {
1829 $sql = "SELECT dol_util_rebuild_sequences();";
1830 print '<!-- '.$sql.' -->';
1831 $resql = $db->query($sql);
1832 }
1833 } else {
1834 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1835 }
1836}
1837
1838//
1839if ($ok && GETPOST('repair_link_dispatch_lines_supplier_order_lines')) {
1840 /*
1841 * This script is meant to be run when upgrading from a dolibarr version < 3.8
1842 * to a newer version.
1843 *
1844 * Version 3.8 introduces a new column in llx_commande_fournisseur_dispatch, which
1845 * matches the dispatch to a specific supplier order line (so that if there are
1846 * several with the same product, the user can specifically tell which products of
1847 * which line were dispatched where).
1848 *
1849 * However when migrating, the new column has a default value of 0, which means that
1850 * old supplier orders whose lines were dispatched using the old dolibarr version
1851 * have unspecific dispatch lines, which are not taken into account by the new version,
1852 * thus making the order look like it was never dispatched at all.
1853 *
1854 * This scripts sets this foreign key to the first matching supplier order line whose
1855 * product (and supplier order of course) are the same as the dispatch’s.
1856 *
1857 * If the dispatched quantity is more than indicated on the order line (this happens if
1858 * there are several order lines for the same product), it creates new dispatch lines
1859 * pointing to the other order lines accordingly, until all the dispatched quantity is
1860 * accounted for.
1861 */
1862
1863 $repair_link_dispatch_lines_supplier_order_lines = GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha');
1864
1865
1866 echo '<tr><th>Repair llx_receptiondet_batch.fk_commandefourndet</th></tr>';
1867 echo '<tr><td>Repair in progress. This may take a while.</td></tr>';
1868
1869 $sql_dispatch = 'SELECT * FROM '.MAIN_DB_PREFIX.'receptiondet_batch WHERE COALESCE(fk_elementdet, 0) = 0';
1870 $db->begin();
1871 $resql_dispatch = $db->query($sql_dispatch);
1872 $n_processed_rows = 0;
1873 $errors = array();
1874 if ($resql_dispatch) {
1875 if ($db->num_rows($resql_dispatch) == 0) {
1876 echo '<tr><td>Nothing to do.</td></tr>';
1877 exit;
1878 }
1879 while ($obj_dispatch = $db->fetch_object($resql_dispatch)) {
1880 $sql_line = 'SELECT line.rowid, line.qty FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet AS line';
1881 $sql_line .= ' WHERE line.fk_commande = '.((int) $obj_dispatch->fk_commande);
1882 $sql_line .= ' AND line.fk_product = '.((int) $obj_dispatch->fk_product);
1883 $resql_line = $db->query($sql_line);
1884
1885 // s’il y a plusieurs lignes avec le même produit sur cette commande fournisseur,
1886 // on divise la ligne de dispatch en autant de lignes qu’on en a sur la commande pour le produit
1887 // et on met la quantité de la ligne dans la limit du "budget" indiqué par dispatch.qty
1888
1889 $remaining_qty = $obj_dispatch->qty;
1890 $first_iteration = true;
1891 if (!$resql_line) {
1892 echo '<tr><td>Unable to find a matching supplier order line for dispatch #'.$obj_dispatch->rowid.'</td></tr>';
1893 $errors[] = $sql_line;
1894 $n_processed_rows++;
1895 continue;
1896 }
1897 if ($db->num_rows($resql_line) == 0) {
1898 continue;
1899 }
1900 while ($obj_line = $db->fetch_object($resql_line)) {
1901 if (!$remaining_qty) {
1902 break;
1903 }
1904 if (!$obj_line->rowid) {
1905 continue;
1906 }
1907 $qty_for_line = min($remaining_qty, $obj_line->qty);
1908 if ($first_iteration) {
1909 $sql_attach = 'UPDATE '.MAIN_DB_PREFIX.'receptiondet_batch';
1910 $sql_attach .= ' SET fk_elementdet = '.((int) $obj_line->rowid).', qty = '.((float) $qty_for_line);
1911 $sql_attach .= ' WHERE rowid = '.((int) $obj_dispatch->rowid);
1912 $first_iteration = false;
1913 } else {
1914 $sql_attach_values = array(
1915 (string) ((int) $obj_dispatch->fk_element),
1916 (string) ((int) $obj_dispatch->fk_product),
1917 (string) ((int) $obj_line->rowid),
1918 (string) ((float) $qty_for_line),
1919 (string) ((int) $obj_dispatch->fk_entrepot),
1920 (string) ((int) $obj_dispatch->fk_user),
1921 $obj_dispatch->datec ? "'".$db->idate($db->jdate($obj_dispatch->datec))."'" : 'NULL',
1922 $obj_dispatch->comment ? "'".$db->escape($obj_dispatch->comment)."'" : 'NULL',
1923 $obj_dispatch->status ? (string) ((int) $obj_dispatch->status) : 'NULL',
1924 $obj_dispatch->tms ? "'".$db->idate($db->jdate($obj_dispatch->tms))."'" : 'NULL',
1925 $obj_dispatch->batch ? "'".$db->escape($obj_dispatch->batch)."'" : 'NULL',
1926 $obj_dispatch->eatby ? "'".$db->escape($obj_dispatch->eatby)."'" : 'NULL',
1927 $obj_dispatch->sellby ? "'".$db->escape($obj_dispatch->sellby)."'" : 'NULL'
1928 );
1929 $sql_attach_values = implode(', ', $sql_attach_values);
1930
1931 $sql_attach = 'INSERT INTO '.MAIN_DB_PREFIX.'receptiondet_batch';
1932 $sql_attach .= ' (fk_element, fk_product, fk_elementdet, qty, fk_entrepot, fk_user, datec, comment, status, tms, batch, eatby, sellby)';
1933 $sql_attach .= " VALUES (".$sql_attach_values.")"; // The string is already sanitized
1934 }
1935
1936 if ($repair_link_dispatch_lines_supplier_order_lines == 'confirmed') {
1937 $resql_attach = $db->query($sql_attach);
1938 } else {
1939 $resql_attach = true; // Force success in test mode
1940 }
1941
1942 if ($resql_attach) {
1943 $remaining_qty -= $qty_for_line;
1944 } else {
1945 $errors[] = $sql_attach;
1946 }
1947
1948 $first_iteration = false;
1949 }
1950 $n_processed_rows++;
1951
1952 // report progress every 256th row
1953 if (!($n_processed_rows & 0xff)) {
1954 echo '<tr><td>Processed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1955 flush();
1956 if (ob_get_level() > 0) {
1957 ob_flush();
1958 }
1959 }
1960 }
1961 } else {
1962 echo '<tr><td>Unable to find any dispatch without an fk_commandefourndet.'."</td></tr>\n";
1963 echo $sql_dispatch."\n";
1964 }
1965 echo '<tr><td>Fixed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1966 echo '<tr><td>DONE.'."</td></tr>\n";
1967
1968 if (count($errors)) {
1969 $db->rollback();
1970 echo '<tr><td>The transaction was rolled back due to errors: nothing was changed by the script.</td></tr>';
1971 } else {
1972 $db->commit();
1973 }
1974 $db->close();
1975
1976 echo '<tr><td><h3>SQL queries with errors:</h3></tr></td>';
1977 echo '<tr><td>'.implode('</td></tr><tr><td>', $errors).'</td></tr>';
1978}
1979
1980// Repair llx_commande_fournisseur to eliminate duplicate reference
1981if ($ok && GETPOST('repair_supplier_order_duplicate_ref')) {
1982 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php';
1983 include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1984
1985 $db->begin();
1986
1987 $err = 0;
1988
1989 // Query to find all duplicate supplier orders
1990 $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
1991 $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)";
1992
1993 // Build a list of ref => []CommandeFournisseur
1994 $duplicateSupplierOrders = [];
1995 $resql = $db->query($sql);
1996 if ($resql) {
1997 while ($rawSupplierOrder = $db->fetch_object($resql)) {
1998 $supplierOrder = new CommandeFournisseur($db);
1999 $supplierOrder->setVarsFromFetchObj($rawSupplierOrder);
2000
2001 $duplicateSupplierOrders[$rawSupplierOrder->ref] [] = $supplierOrder;
2002 }
2003 } else {
2004 $err++;
2005 }
2006
2007 // Process all duplicate supplier order and regenerate the reference for all except the first one
2008 foreach ($duplicateSupplierOrders as $ref => $supplierOrders) {
2010 foreach (array_slice($supplierOrders, 1) as $supplierOrder) {
2011 // Definition of supplier order numbering model name
2012 $soc = new Societe($db);
2013 $soc->fetch((int) $supplierOrder->fourn_id);
2014
2015 $newRef = $supplierOrder->getNextNumRef($soc);
2016
2017 $sql = "UPDATE " . MAIN_DB_PREFIX . "commande_fournisseur cf SET cf.ref = '" . $db->escape($newRef) . "' WHERE cf.rowid = " . (int) $supplierOrder->id;
2018 if (!$db->query($sql)) {
2019 $err++;
2020 }
2021 }
2022 }
2023
2024 if ($err == 0) {
2025 $db->commit();
2026 } else {
2027 $db->rollback();
2028 }
2029}
2030
2031// Repair llx_invoice to calculate totals from line items
2032// WARNING : The process can be long on production environments due to restrictions.
2033// consider raising php_max_execution time if failing to execute completely.
2034if ($ok && GETPOST('recalculateinvoicetotal') == 'confirmed') {
2035 $err = 0;
2036 $db->begin();
2037 $sql = "
2038 SELECT
2039 f.rowid,
2040 SUM(fd.total_ht) as total_ht
2041 FROM ".MAIN_DB_PREFIX."facture f
2042 LEFT JOIN ".MAIN_DB_PREFIX."facturedet fd
2043 ON fd.fk_facture = f.rowid
2044 WHERE f.total_ht = 0
2045 GROUP BY fd.fk_facture HAVING SUM(fd.total_ht) <> 0";
2046 $resql = $db->query($sql);
2047 if ($resql) {
2048 $num = $db->num_rows($resql);
2049 print "We found ".$num." factures qualified that will have their total recalculated because they are at zero and line items not at zero\n";
2050 dol_syslog("We found ".$num." factures qualified that will have their total recalculated because they are at zero and line items not at zero");
2051
2052 if ($num) {
2053 $i = 0;
2054 while ($i < $num) {
2055 $obj = $db->fetch_object($resql);
2056 $sql_calculs = "
2057 SELECT
2058 SUM(fd.total_ht) as 'total_ht',
2059 SUM(fd.total_tva) as 'total_tva',
2060 SUM(fd.total_localtax1) as 'localtax1',
2061 SUM(fd.total_localtax2) as 'localtax2',
2062 SUM(fd.total_ttc) as 'total_ttc'
2063 FROM
2064 ".MAIN_DB_PREFIX."facturedet fd
2065 WHERE
2066 fd.fk_facture = $obj->rowid";
2067 $ressql_calculs = $db->query($sql_calculs);
2068 while ($obj_calcul = $db->fetch_object($ressql_calculs)) {
2069 // Calcul de la somme des paiements reçus
2070 $sql_paiements = "SELECT SUM(amount) as somme from ".MAIN_DB_PREFIX."paiement_facture WHERE fk_facture = $obj->rowid";
2071 $montantPaiements = $db->fetch_object($db->query($sql_paiements))->somme;
2072 $totHt= ($obj_calcul->total_ht ? price2num($obj_calcul->total_ht, 'MT') : 0);
2073 $totTva = ($obj_calcul->total_tva ? price2num($obj_calcul->total_tva, 'MT') : 0);
2074 $totLocal1 = ($obj_calcul->localtax1 ? price2num($obj_calcul->localtax1, 'MT') : 0);
2075 $totLocal2 = ($obj_calcul->localtax2 ? price2num($obj_calcul->localtax2, 'MT') : 0);
2076 $totTtc = $totHt + $totTva + $totLocal1 + $totLocal2;
2077 $sql_maj = "
2078 UPDATE ".MAIN_DB_PREFIX."facture
2079 SET
2080 total_ht = $totHt,
2081 total_tva = $totTva,
2082 localtax1 = $totLocal1,
2083 localtax2 = $totLocal2,
2084 total_ttc = $totTtc,
2085 fk_statut = ".($totTtc == price2num($montantPaiements, 'MT') ? 2 : 1 ).",
2086 paid = ".($totTtc == price2num($montantPaiements, 'MT') ? 1 : 0 )."
2087 WHERE
2088 rowid = $obj->rowid";
2089 $db->query($sql_maj);
2090 }
2091 $i++;
2092 }
2093 } else {
2094 print "Pas de factures à traiter\n";
2095 }
2096 } else {
2097 dol_print_error($db);
2098 dol_syslog("calculate_total_and_taxes.php: Error");
2099 $err++;
2100 }
2101
2102 if ($err == 0) {
2103 $db->commit();
2104 } else {
2105 $db->rollback();
2106 }
2107}
2108
2109// Repair mailing path
2110if ($ok && GETPOST('repair_mailing_path')) {
2111 global $user;
2112 $sav_user = is_object($user) ? clone $user : $user;
2113
2114 require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php';
2115 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
2116
2117 print '<tr><td colspan="2"><br>*** Repair mailing path<br>';
2118
2125 function migrate_mailing_filespath($mailing)
2126 {
2127 global $db, $conf, $user;
2128
2129 $dir = $conf->mailing->dir_output;
2130 $origin = $dir.'/'.get_exdir($mailing->id, 2, 0, 1, $mailing, 'mailing');
2131 $destin = $dir.'/'.get_exdir($mailing->id, 0, 0, 1, $mailing, 'mailing');
2132
2133 $origin_osencoded = dol_osencode($origin);
2134 $destin_osencoded = dol_osencode($destin);
2135 dol_mkdir($destin);
2136
2137 $user = new User($db);
2138 $user->fetch($mailing->user_creation_id);
2139
2140 if (dol_is_dir($origin)) {
2141 $handle = opendir($origin_osencoded);
2142 if (is_resource($handle)) {
2143 while (($file = readdir($handle)) !== false) {
2144 if ($file != '.' && $file != '..' && is_dir($origin_osencoded.'/'.$file)) {
2145 $thumbs = opendir($origin_osencoded.'/'.$file);
2146 if (is_resource($thumbs)) {
2147 dol_mkdir($destin.'/'.$file);
2148 while (($thumb = readdir($thumbs)) !== false) {
2149 $res = dol_move($origin.'/'.$file.'/'.$thumb, $destin.'/'.$file.'/'.$thumb);
2150 $msg = ($res ? ' * Migration successful' : 'Migration failed') . ' for file '.$origin.'/'.$file.'.<br>';
2151 print ($msg);
2152 }
2153 // dol_delete_dir($origin.'/'.$file);
2154 }
2155 } else {
2156 if (dol_is_file($origin.'/'.$file)) {
2157 $res = dol_move($origin.'/'.$file, $destin.'/'.$file);
2158 $msg = ($res ? ' * Migration successful' : 'Migration failed') . ' for file '.$origin.'/'.$file.'.<br>';
2159 print ($msg);
2160 }
2161 }
2162 }
2163 }
2164 }
2165 }
2166
2167 $mailing = new Mailing($db);
2168
2169 $sql = "SELECT rowid as mid from ".MAIN_DB_PREFIX."mailing"; // Get list of all mailing
2170 $resql = $db->query($sql);
2171 if ($resql) {
2172 while ($obj = $db->fetch_object($resql)) {
2173 $mailing->fetch($obj->mid);
2174 print "Migrating mailing id=".$mailing->id." ref=".$mailing->ref."<br>\n";
2175 migrate_mailing_filespath($mailing);
2176 }
2177 } else {
2178 $ok = 0;
2179 dol_print_error($db);
2180 }
2181
2182 $user = $sav_user;
2183
2184 print '</td></tr>';
2185}
2186
2187print '</table>';
2188
2189if (empty($actiondone)) {
2190 print '<div class="error">'.$langs->trans("ErrorWrongParameters").'</div>';
2191}
2192
2193if ($oneoptionset) {
2194 print '<br>';
2195 print '<div class="center" style="padding-top: 10px"><a href="../index.php?mainmenu=home&leftmenu=home'.(GETPOSTISSET("login") ? '&username='.urlencode(GETPOST("login")) : '').'">';
2196 print img_picto('', 'url', 'class="pictofixedwidth"');
2197 print $langs->trans("GoToDolibarr");
2198 print '</a></div>';
2199}
2200
2201dolibarr_install_syslog("--- repair: end");
2202pFooter(1, $setuplang);
2203
2204if ($db->connected) {
2205 $db->close();
2206}
2207
2208// Return code if ran from command line
2209if (!$ok && isset($argv[1])) {
2210 exit(1);
2211}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
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.
Class for managing the social charges.
Class to manage predefined suppliers products.
Class to manage customers orders.
Class to manage standard extra fields.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
Class to manage emailings module.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
$conffile
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array(), $entity=null)
Move a file into another name.
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
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.
dol_delete_dir($dir, $nophperrors=0)
Remove a directory (not recursive, so content must be empty).
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($utf8_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:64
dol_is_dir($folder)
Test if filename is a directory.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
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).
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
pHeader($subtitle, $next, $action='set', $param='', $forcejqueryurl='', $csstable='main-inside')
Show HTML header of install pages.
Definition inc.php:541
pFooter($nonext=0, $setuplang='', $jscheckfunction='', $withpleasewait=0, $morehtml='')
Print HTML footer of install pages.
Definition inc.php:635
dolibarr_install_syslog($message, $level=LOG_DEBUG)
Log function for install pages.
Definition inc.php:699
clean_data_ecm_directories()
Clean data into ecm_directories table.
dol_decode($chain, $key='1')
Decode a base 64 encoded + specific delta change.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.