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