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