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