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