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