dolibarr 21.0.0-alpha
repair.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
6 * Copyright (C) 2021-2024 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
8 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 Vincent de Grandpré <vincent@de-grandpre.quebec>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
30include_once 'inc.php';
31if (file_exists($conffile)) {
32 include_once $conffile;
33}
34require_once $dolibarr_main_document_root.'/core/lib/admin.lib.php';
35include_once $dolibarr_main_document_root.'/core/lib/images.lib.php';
36require_once $dolibarr_main_document_root.'/core/class/extrafields.class.php';
37require_once 'lib/repair.lib.php';
38
39$step = 2;
40$ok = 0;
41
42
43// Cette page peut etre longue. On augmente le delai autorise.
44// Ne fonctionne que si on est pas en safe_mode.
45$err = error_reporting();
46error_reporting(0);
47@set_time_limit(120);
48error_reporting($err);
49
50$setuplang = GETPOST("selectlang", 'aZ09', 3) ? GETPOST("selectlang", 'aZ09', 3) : 'auto';
51$langs->setDefaultLang($setuplang);
52
53$langs->loadLangs(array("admin", "install", "other"));
54
55if ($dolibarr_main_db_type == "mysqli") {
56 $choix = 1;
57}
58if ($dolibarr_main_db_type == "pgsql") {
59 $choix = 2;
60}
61if ($dolibarr_main_db_type == "mssql") {
62 $choix = 3;
63}
64
65
66dolibarr_install_syslog("--- repair: entering upgrade.php page");
67if (!is_object($conf)) {
68 dolibarr_install_syslog("repair: conf file not initialized", LOG_ERR);
69}
70
71
72/*
73 * View
74 */
75
76pHeader('', "upgrade2", GETPOST('action', 'aZ09'));
77
78// Action to launch the repair script
79$actiondone = 1;
80
81print '<h3>'.$langs->trans("Repair").'</h3>';
82
83print '<div class="warning" style="padding-top: 10px">';
84print $langs->trans("SetAtLeastOneOptionAsUrlParameter");
85print '</div>';
86
87//print 'You must set one of the following option with a parameter value that is "test" or "confirmed" on the URL<br>';
88//print $langs->trans("Example").': '.DOL_MAIN_URL_ROOT.'/install/repair.php?standard=confirmed<br>'."\n";
89print '<br>';
90
91print 'Option standard is '.(GETPOST('standard', 'alpha') ? GETPOST('standard', 'alpha') : 'undefined').'<br>'."\n";
92// Disable modules
93print 'Option force_disable_of_modules_not_found is '.(GETPOST('force_disable_of_modules_not_found', 'alpha') ? GETPOST('force_disable_of_modules_not_found', 'alpha') : 'undefined').'<br>'."\n";
94// Files
95print 'Option restore_thirdparties_logos is '.(GETPOST('restore_thirdparties_logos', 'alpha') ? GETPOST('restore_thirdparties_logos', 'alpha') : 'undefined').'<br>'."\n";
96print 'Option restore_user_pictures is '.(GETPOST('restore_user_pictures', 'alpha') ? GETPOST('restore_user_pictures', 'alpha') : 'undefined').'<br>'."\n";
97print 'Option rebuild_product_thumbs is '.(GETPOST('rebuild_product_thumbs', 'alpha') ? GETPOST('rebuild_product_thumbs', 'alpha') : 'undefined').'<br>'."\n";
98// Clean tables and data
99print 'Option clean_linked_elements is '.(GETPOST('clean_linked_elements', 'alpha') ? GETPOST('clean_linked_elements', 'alpha') : 'undefined').'<br>'."\n";
100print 'Option clean_menus is '.(GETPOST('clean_menus', 'alpha') ? GETPOST('clean_menus', 'alpha') : 'undefined').'<br>'."\n";
101print 'Option clean_orphelin_dir is '.(GETPOST('clean_orphelin_dir', 'alpha') ? GETPOST('clean_orphelin_dir', 'alpha') : 'undefined').'<br>'."\n";
102print 'Option clean_product_stock_batch is '.(GETPOST('clean_product_stock_batch', 'alpha') ? GETPOST('clean_product_stock_batch', 'alpha') : 'undefined').'<br>'."\n";
103print 'Option clean_perm_table is '.(GETPOST('clean_perm_table', 'alpha') ? GETPOST('clean_perm_table', 'alpha') : 'undefined').'<br>'."\n";
104print 'Option repair_link_dispatch_lines_supplier_order_lines, is '.(GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha') ? GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha') : 'undefined').'<br>'."\n";
105// Init data
106print 'Option set_empty_time_spent_amount is '.(GETPOST('set_empty_time_spent_amount', 'alpha') ? GETPOST('set_empty_time_spent_amount', 'alpha') : 'undefined').'<br>'."\n";
107// Structure
108print 'Option force_utf8_on_tables (force utf8 + row=dynamic), for mysql/mariadb only, is '.(GETPOST('force_utf8_on_tables', 'alpha') ? GETPOST('force_utf8_on_tables', 'alpha') : 'undefined').'<br>'."\n";
109print '<span class="valignmiddle">'."Option force_utf8mb4_on_tables (force utf8mb4 + row=dynamic, EXPERIMENTAL!), for mysql/mariadb only, is ".(GETPOST('force_utf8mb4_on_tables', 'alpha') ? GETPOST('force_utf8mb4_on_tables', 'alpha') : 'undefined');
110print '</span>';
111if ($dolibarr_main_db_character_set != 'utf8mb4') {
112 print '<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.">';
113}
114print "<br>\n";
115print "Option force_collation_from_conf_on_tables (force ".$conf->db->character_set."/".$conf->db->dolibarr_main_db_collation." + row=dynamic), for mysql/mariadb only is ".(GETPOST('force_collation_from_conf_on_tables', 'alpha') ? GETPOST('force_collation_from_conf_on_tables', 'alpha') : 'undefined')."<br>\n";
116
117// Rebuild sequence
118print 'Option rebuild_sequences, for postgresql only, is '.(GETPOST('rebuild_sequences', 'alpha') ? GETPOST('rebuild_sequences', 'alpha') : 'undefined').'<br>'."\n";
119print '<br>';
120
121print '<hr>';
122
123print '<table cellspacing="0" cellpadding="1" class="centpercent">';
124$error = 0;
125
126// If password is encoded, we decode it
127if (preg_match('/crypted:/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
128 require_once $dolibarr_main_document_root.'/core/lib/security.lib.php';
129 if (preg_match('/crypted:/i', $dolibarr_main_db_pass)) {
130 $dolibarr_main_db_pass = preg_replace('/crypted:/i', '', $dolibarr_main_db_pass);
131 $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_pass);
132 $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
133 } else {
134 $dolibarr_main_db_pass = dol_decode($dolibarr_main_db_encrypted_pass);
135 }
136}
137
138// $conf is already instancied inside inc.php
139$conf->db->type = $dolibarr_main_db_type;
140$conf->db->host = $dolibarr_main_db_host;
141$conf->db->port = $dolibarr_main_db_port;
142$conf->db->name = $dolibarr_main_db_name;
143$conf->db->user = $dolibarr_main_db_user;
144$conf->db->pass = $dolibarr_main_db_pass;
145
146// For encryption
147$conf->db->dolibarr_main_db_encryption = isset($dolibarr_main_db_encryption) ? $dolibarr_main_db_encryption : 0;
148$conf->db->dolibarr_main_db_cryptkey = isset($dolibarr_main_db_cryptkey) ? $dolibarr_main_db_cryptkey : '';
149
150$db = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, (int) $conf->db->port);
151
152if ($db->connected) {
153 print '<tr><td class="nowrap">';
154 print $langs->trans("ServerConnection")." : $dolibarr_main_db_host</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
155 dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerConnection").": ".$dolibarr_main_db_host.$langs->transnoentities("OK"));
156 $ok = 1;
157} else {
158 print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->transnoentities("Error")."</td></tr>";
159 dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
160 $ok = 0;
161}
162
163if ($ok) {
164 if ($db->database_selected) {
165 print '<tr><td class="nowrap">';
166 print $langs->trans("DatabaseConnection")." : ".$dolibarr_main_db_name."</td><td class=\"right\">".$langs->trans("OK")."</td></tr>";
167 dolibarr_install_syslog("repair: database connection successful: ".$dolibarr_main_db_name);
168 $ok = 1;
169 } else {
170 print "<tr><td>".$langs->trans("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name)."</td><td class=\"right\">".$langs->trans("Error")."</td></tr>";
171 dolibarr_install_syslog("repair: ".$langs->transnoentities("ErrorFailedToConnectToDatabase", $dolibarr_main_db_name));
172 $ok = 0;
173 }
174}
175
176// Show database version
177if ($ok) {
178 $version = $db->getVersion();
179 $versionarray = $db->getVersionArray();
180 print '<tr><td>'.$langs->trans("ServerVersion").'</td>';
181 print '<td class="right">'.$version.'</td></tr>';
182 dolibarr_install_syslog("repair: ".$langs->transnoentities("ServerVersion").": ".$version);
183 //print '<td class="right">'.join('.',$versionarray).'</td></tr>';
184}
185
186$conf->setValues($db);
187// Reset forced setup after the setValues
188if (defined('SYSLOG_FILE')) {
189 $conf->global->SYSLOG_FILE = constant('SYSLOG_FILE');
190}
191$conf->global->MAIN_ENABLE_LOG_TO_HTML = 1;
192
193
194/* Start action here */
195$oneoptionset = 0;
196$oneoptionset = (GETPOST('standard', 'alpha') || GETPOST('restore_thirdparties_logos', 'alpha') || GETPOST('clean_linked_elements', 'alpha') || GETPOST('clean_menus', 'alpha')
197 || GETPOST('clean_orphelin_dir', 'alpha') || GETPOST('clean_product_stock_batch', 'alpha') || GETPOST('set_empty_time_spent_amount', 'alpha') || GETPOST('rebuild_product_thumbs', 'alpha')
198 || GETPOST('clean_perm_table', 'alpha')
199 || GETPOST('force_disable_of_modules_not_found', 'alpha')
200 || GETPOST('force_utf8_on_tables', 'alpha') || GETPOST('force_utf8mb4_on_tables', 'alpha') || GETPOST('force_collation_from_conf_on_tables', 'alpha')
201 || GETPOST('rebuild_sequences', 'alpha') || GETPOST('recalculateinvoicetotal', 'alpha'));
202
203if ($ok && $oneoptionset) {
204 // Show wait message
205 print '<tr><td colspan="2">'.$langs->trans("PleaseBePatient").'<br><br></td></tr>';
206 flush();
207}
208
209
210// run_sql: Run repair SQL file
211if ($ok && GETPOST('standard', 'alpha')) {
212 $dir = "mysql/migration/";
213
214 $filelist = array();
215 $i = 0;
216 $ok = 0;
217
218 // Recupere list fichier
219 $filesindir = array();
220 $handle = opendir($dir);
221 if (is_resource($handle)) {
222 while (($file = readdir($handle)) !== false) {
223 if (preg_match('/\.sql$/i', $file)) {
224 $filesindir[] = $file;
225 }
226 }
227 }
228 sort($filesindir);
229
230 foreach ($filesindir as $file) {
231 if (preg_match('/repair/i', $file)) {
232 $filelist[] = $file;
233 }
234 }
235
236 // Loop on each file
237 foreach ($filelist as $file) {
238 print '<tr><td class="nowrap">*** ';
239 print $langs->trans("Script").'</td><td class="right">'.$file.'</td></tr>';
240
241 $name = substr($file, 0, dol_strlen($file) - 4);
242
243 // Run sql script
244 $ok = run_sql($dir.$file, 0, '', 1);
245 }
246}
247
248
249// sync_extrafields: Search list of fields declared and list of fields created into databases, then create fields missing
250
251if ($ok && GETPOST('standard', 'alpha')) {
252 $extrafields = new ExtraFields($db);
253
254 // List of tables that has an extrafield table
255 $listofmodulesextra = array('societe' => 'societe', 'adherent' => 'adherent', 'product' => 'product',
256 'socpeople' => 'socpeople', 'propal' => 'propal', 'commande' => 'commande',
257 'facture' => 'facture', 'facturedet' => 'facturedet', 'facture_rec' => 'facture_rec', 'facturedet_rec' => 'facturedet_rec',
258 'supplier_proposal' => 'supplier_proposal', 'commande_fournisseur' => 'commande_fournisseur',
259 'facture_fourn' => 'facture_fourn', 'facture_fourn_rec' => 'facture_fourn_rec', 'facture_fourn_det' => 'facture_fourn_det', 'facture_fourn_det_rec' => 'facture_fourn_det_rec',
260 'fichinter' => 'fichinter', 'fichinterdet' => 'fichinterdet',
261 'inventory' => 'inventory',
262 'actioncomm' => 'actioncomm', 'bom_bom' => 'bom_bom', 'mrp_mo' => 'mrp_mo',
263 'adherent_type' => 'adherent_type', 'user' => 'user', 'partnership' => 'partnership', 'projet' => 'projet', 'projet_task' => 'projet_task', 'ticket' => 'ticket');
264 //$listofmodulesextra = array('fichinter'=>'fichinter');
265
266 print '<tr><td colspan="2"><br>*** Check fields into extra table structure match table of definition. If not add column into table</td></tr>';
267 foreach ($listofmodulesextra as $tablename => $elementtype) {
268 // Get list of fields
269 $tableextra = MAIN_DB_PREFIX.$tablename.'_extrafields';
270
271 // Define $arrayoffieldsdesc
272 $arrayoffieldsdesc = $extrafields->fetch_name_optionals_label($elementtype);
273
274 // Define $arrayoffieldsfound
275 $arrayoffieldsfound = array();
276 $resql = $db->DDLDescTable($tableextra);
277 if ($resql) {
278 print '<tr><td>Check availability of extra field for '.$tableextra;
279 $i = 0;
280 while ($obj = $db->fetch_object($resql)) {
281 $fieldname = $fieldtype = '';
282 if (preg_match('/mysql/', $db->type)) {
283 $fieldname = $obj->Field;
284 $fieldtype = $obj->Type;
285 } else {
286 $fieldname = isset($obj->Key) ? $obj->Key : $obj->attname;
287 $fieldtype = isset($obj->Type) ? $obj->Type : 'varchar';
288 }
289
290 if (empty($fieldname)) {
291 continue;
292 }
293 if (in_array($fieldname, array('rowid', 'tms', 'fk_object', 'import_key'))) {
294 continue;
295 }
296 $arrayoffieldsfound[$fieldname] = array('type' => $fieldtype);
297 }
298 print ' - Found '.count($arrayoffieldsfound).' fields into table';
299 if (count($arrayoffieldsfound) > 0) {
300 print ' <span class="opacitymedium">('.implode(', ', array_keys($arrayoffieldsfound)).')</span>';
301 }
302 print '<br>'."\n";
303
304 // If it does not match, we create fields
305 foreach ($arrayoffieldsdesc as $code => $label) {
306 if (!in_array($code, array_keys($arrayoffieldsfound))) {
307 print 'Found field '.$code.' declared into '.MAIN_DB_PREFIX.'extrafields table but not found into desc of table '.$tableextra." -> ";
308 $type = $extrafields->attributes[$elementtype]['type'][$code];
309 $length = $extrafields->attributes[$elementtype]['size'][$code];
310 $attribute = '';
311 $default = '';
312 $extra = '';
313 $null = 'null';
314
315 if ($type == 'boolean') {
316 $typedb = 'int';
317 $lengthdb = '1';
318 } elseif ($type == 'price') {
319 $typedb = 'double';
320 $lengthdb = '24,8';
321 } elseif ($type == 'phone') {
322 $typedb = 'varchar';
323 $lengthdb = '20';
324 } elseif ($type == 'mail') {
325 $typedb = 'varchar';
326 $lengthdb = '128';
327 } elseif (($type == 'select') || ($type == 'sellist') || ($type == 'radio') || ($type == 'checkbox') || ($type == 'chkbxlst')) {
328 $typedb = 'text';
329 $lengthdb = '';
330 } elseif ($type == 'link') {
331 $typedb = 'int';
332 $lengthdb = '11';
333 } else {
334 $typedb = $type;
335 $lengthdb = $length;
336 }
337
338 $field_desc = array(
339 'type' => $typedb,
340 'value' => $lengthdb,
341 'attribute' => $attribute,
342 'default' => $default,
343 'extra' => $extra,
344 'null' => $null
345 );
346 //var_dump($field_desc);exit;
347
348 $result = 0;
349 if (GETPOST('standard', 'alpha') == 'confirmed') {
350 $result = $db->DDLAddField($tableextra, $code, $field_desc, "");
351
352 if ($result < 0) {
353 print "KO ".$db->lasterror."<br>\n";
354 } else {
355 print "OK<br>\n";
356 }
357 } else {
358 print ' - Mode test, no column added.';
359 }
360 }
361 }
362
363 print "</td><td>&nbsp;</td></tr>\n";
364 } else {
365 print '<tr><td>Table '.$tableextra.' is not found</td><td></td></tr>'."\n";
366 }
367 }
368}
369
370
371// clean_data_ecm_dir: Clean data into ecm_directories table
372if ($ok && GETPOST('standard', 'alpha')) {
374}
375
376
377// clean declaration constants
378if ($ok && GETPOST('standard', 'alpha')) {
379 print '<tr><td colspan="2"><br>*** Clean constant record of modules not enabled</td></tr>';
380
381 $sql = "SELECT name, entity, value";
382 $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
383 $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'";
384 $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'";
385 $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_%'";
386 $sql .= " OR name LIKE 'MAIN_MODULE_%_MODULEFOREXTERNAL'";
387 $sql .= " ORDER BY name, entity";
388
389 $resql = $db->query($sql);
390 if ($resql) {
391 $num = $db->num_rows($resql);
392
393 if ($num) {
394 $db->begin();
395
396 $i = 0;
397 while ($i < $num) {
398 $obj = $db->fetch_object($resql);
399
400 $reg = array();
401 if (preg_match('/MAIN_MODULE_([^_]+)_(.+)/i', $obj->name, $reg)) {
402 $name = $reg[1];
403 $type = $reg[2];
404
405 $sql2 = "SELECT COUNT(*) as nb";
406 $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
407 $sql2 .= " WHERE name = 'MAIN_MODULE_".$name."'";
408 $sql2 .= " AND entity = ".((int) $obj->entity);
409 $resql2 = $db->query($sql2);
410 if ($resql2) {
411 $obj2 = $db->fetch_object($resql2);
412 if ($obj2 && $obj2->nb == 0) {
413 // Module not found, so we can remove entry
414 $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = '".$db->escape($obj->name)."' AND entity = ".((int) $obj->entity);
415
416 if (GETPOST('standard', 'alpha') == 'confirmed') {
417 $db->query($sqldelete);
418
419 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>';
420 } else {
421 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>';
422 }
423 } else {
424 //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>';
425 }
426 }
427 }
428
429 $i++;
430 }
431
432 $db->commit();
433 }
434 } else {
435 dol_print_error($db);
436 }
437}
438
439
440// clean box of not enabled modules
441if ($ok && GETPOST('standard', 'alpha')) {
442 print '<tr><td colspan="2"><br>*** Clean definition of boxes of modules not enabled</td></tr>';
443
444 $sql = "SELECT file, entity FROM ".MAIN_DB_PREFIX."boxes_def";
445 $sql .= " WHERE file like '%@%'";
446
447 $resql = $db->query($sql);
448 if ($resql) {
449 $num = $db->num_rows($resql);
450
451 if ($num) {
452 $db->begin();
453
454 $i = 0;
455 while ($i < $num) {
456 $obj = $db->fetch_object($resql);
457
458 $reg = array();
459 if (preg_match('/^(.+)@(.+)$/i', $obj->file, $reg)) {
460 $name = $reg[1];
461 $module = $reg[2];
462
463 $sql2 = "SELECT COUNT(*) as nb";
464 $sql2 .= " FROM ".MAIN_DB_PREFIX."const as c";
465 $sql2 .= " WHERE name = 'MAIN_MODULE_".strtoupper($module)."'";
466 $sql2 .= " AND entity = ".((int) $obj->entity);
467 $sql2 .= " AND value <> 0";
468 $resql2 = $db->query($sql2);
469 if ($resql2) {
470 $obj2 = $db->fetch_object($resql2);
471 if ($obj2 && $obj2->nb == 0) {
472 // Module not found, so we canremove entry
473 $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).")";
474 $sqldeleteb = "DELETE FROM ".MAIN_DB_PREFIX."boxes_def WHERE file = '".$db->escape($obj->file)."' AND entity = ".((int) $obj->entity);
475
476 if (GETPOST('standard', 'alpha') == 'confirmed') {
477 $db->query($sqldeletea);
478 $db->query($sqldeleteb);
479
480 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>';
481 } else {
482 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>';
483 }
484 } else {
485 //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>';
486 }
487 }
488 }
489
490 $i++;
491 }
492
493 $db->commit();
494 }
495 }
496}
497
498
499// restore_thirdparties_logos: Move logos to correct new directory.
500if ($ok && GETPOST('restore_thirdparties_logos')) {
501 //$exts=array('gif','png','jpg');
502
503 $ext = '';
504
505 print '<tr><td colspan="2"><br>*** Restore thirdparties logo<br>';
506
507 $sql = "SELECT s.rowid, s.nom as name, s.logo FROM ".MAIN_DB_PREFIX."societe as s ORDER BY s.nom";
508 $resql = $db->query($sql);
509 if ($resql) {
510 $num = $db->num_rows($resql);
511 $i = 0;
512
513 while ($i < $num) {
514 $obj = $db->fetch_object($resql);
515
516 /*
517 $name=preg_replace('/é/','',$obj->name);
518 $name=preg_replace('/ /','_',$name);
519 $name=preg_replace('/\'/','',$name);
520 */
521
522 $tmp = explode('.', $obj->logo);
523 $name = $tmp[0];
524 if (isset($tmp[1])) {
525 $ext = '.'.$tmp[1];
526 }
527
528 if (!empty($name)) {
529 $filetotest = $dolibarr_main_data_root.'/societe/logos/'.$name.$ext;
530 $filetotestsmall = $dolibarr_main_data_root.'/societe/logos/thumbs/'.$name.'_small'.$ext;
531 $exists = (int) dol_is_file($filetotest);
532 print 'Check thirdparty '.$obj->rowid.' name='.$obj->name.' logo='.$obj->logo.' file '.$filetotest." exists=".$exists."<br>\n";
533 if ($exists) {
534 $filetarget = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/'.$name.$ext;
535 $filetargetsmall = $dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs/'.$name.'_small'.$ext;
536 $existt = dol_is_file($filetarget);
537 if (!$existt) {
538 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
539 dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos');
540 }
541
542 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
543 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
544 dol_copy($filetotest, $filetarget, '', 0);
545 }
546 }
547
548 $existtt = dol_is_file($filetargetsmall);
549 if (!$existtt) {
550 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
551 dol_mkdir($dolibarr_main_data_root.'/societe/'.$obj->rowid.'/logos/thumbs');
552 }
553 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
554 if (GETPOST('restore_thirdparties_logos', 'alpha') == 'confirmed') {
555 dol_copy($filetotestsmall, $filetargetsmall, '', 0);
556 }
557 }
558 }
559 }
560
561 $i++;
562 }
563 } else {
564 $ok = 0;
565 dol_print_error($db);
566 }
567
568 print '</td></tr>';
569}
570
571
572
573// restore_user_pictures: Move pictures to correct new directory.
574if ($ok && GETPOST('restore_user_pictures', 'alpha')) {
575 //$exts=array('gif','png','jpg');
576
577 $ext = '';
578
579 print '<tr><td colspan="2"><br>*** Restore user pictures<br>';
580
581 $sql = "SELECT s.rowid, s.firstname, s.lastname, s.login, s.photo FROM ".MAIN_DB_PREFIX."user as s ORDER BY s.rowid";
582 $resql = $db->query($sql);
583 if ($resql) {
584 $num = $db->num_rows($resql);
585 $i = 0;
586
587 while ($i < $num) {
588 $obj = $db->fetch_object($resql);
589
590 /*
591 $name=preg_replace('/é/','',$obj->name);
592 $name=preg_replace('/ /','_',$name);
593 $name=preg_replace('/\'/','',$name);
594 */
595
596 $tmp = explode('.', $obj->photo);
597 $name = $tmp[0];
598 if (isset($tmp[1])) {
599 $ext = '.'.$tmp[1];
600 }
601
602 if (!empty($name)) {
603 $filetotest = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/'.$name.$ext;
604 $filetotestsmall = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_small'.$ext;
605 $filetotestmini = $dolibarr_main_data_root.'/users/'.substr(sprintf('%08d', $obj->rowid), -1, 1).'/'.substr(sprintf('%08d', $obj->rowid), -2, 1).'/thumbs/'.$name.'_mini'.$ext;
606 $exists = (int) dol_is_file($filetotest);
607 print 'Check user '.$obj->rowid.' lastname='.$obj->lastname.' firstname='.$obj->firstname.' photo='.$obj->photo.' file '.$filetotest." exists=".$exists."<br>\n";
608 if ($exists) {
609 $filetarget = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/'.$name.$ext;
610 $filetargetsmall = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_small'.$ext;
611 $filetargetmini = $dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs/'.$name.'_mini'.$ext;
612
613 $existt = dol_is_file($filetarget);
614 if (!$existt) {
615 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
616 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid);
617 }
618
619 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotest." -> ".$filetarget."<br>\n";
620 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
621 dol_copy($filetotest, $filetarget, '', 0);
622 }
623 }
624
625 $existtt = dol_is_file($filetargetsmall);
626 if (!$existtt) {
627 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
628 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
629 }
630
631 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestsmall." -> ".$filetargetsmall."<br>\n";
632 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
633 dol_copy($filetotestsmall, $filetargetsmall, '', 0);
634 }
635 }
636
637 $existtt = dol_is_file($filetargetmini);
638 if (!$existtt) {
639 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
640 dol_mkdir($dolibarr_main_data_root.'/users/'.$obj->rowid.'/thumbs');
641 }
642
643 print " &nbsp; &nbsp; &nbsp; -> Copy file ".$filetotestmini." -> ".$filetargetmini."<br>\n";
644 if (GETPOST('restore_user_pictures', 'alpha') == 'confirmed') {
645 dol_copy($filetotestmini, $filetargetmini, '', 0);
646 }
647 }
648 }
649 }
650
651 $i++;
652 }
653 } else {
654 $ok = 0;
655 dol_print_error($db);
656 }
657
658 print '</td></tr>';
659}
660
661
662// rebuild_product_thumbs: Rebuild thumbs for product files
663if ($ok && GETPOST('rebuild_product_thumbs', 'alpha')) {
664 $ext = '';
665 global $maxwidthsmall, $maxheightsmall, $maxwidthmini, $maxheightmini;
666
667 print '<tr><td colspan="2"><br>*** Rebuild product thumbs<br>';
668
669 $sql = "SELECT s.rowid, s.ref FROM ".MAIN_DB_PREFIX."product as s ORDER BY s.ref";
670 $resql = $db->query($sql);
671 if ($resql) {
672 $num = $db->num_rows($resql);
673 $i = 0;
674
675 while ($i < $num) {
676 $obj = $db->fetch_object($resql);
677
678 if (!empty($obj->ref)) {
679 $files = dol_dir_list($dolibarr_main_data_root.'/produit/'.$obj->ref, 'files', 0);
680 foreach ($files as $file) {
681 // Generate thumbs.
682 if (image_format_supported($file['fullname']) == 1) {
683 $imgThumbSmall = 'notbuild';
684 if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
685 // Used on logon for example
686 $imgThumbSmall = vignette($file['fullname'], $maxwidthsmall, $maxheightsmall, '_small', 50, "thumbs");
687 }
688 print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbSmall." maxwidthsmall=".$maxwidthsmall." maxheightsmall=".$maxheightsmall."<br>\n";
689 $imgThumbMini = 'notbuild';
690 if (GETPOST('rebuild_product_thumbs', 'alpha') == 'confirmed') {
691 // Create mini thumbs for image (Ratio is near 16/9)
692 // Used on menu or for setup page for example
693 $imgThumbMini = vignette($file['fullname'], $maxwidthmini, $maxheightmini, '_mini', 50, "thumbs");
694 }
695 print 'Check product '.$obj->rowid.", file ".$file['fullname']." -> ".$imgThumbMini." maxwidthmini=".$maxwidthmini." maxheightmini=".$maxheightmini."<br>\n";
696 }
697 }
698 }
699
700 $i++;
701 }
702 } else {
703 $ok = 0;
704 dol_print_error($db);
705 }
706
707 print '</td></tr>';
708}
709
710// clean_linked_elements: Check and clean linked elements
711if ($ok && GETPOST('clean_linked_elements', 'alpha')) {
712 print '<tr><td colspan="2"><br>*** Check table of linked elements and delete orphelins links</td></tr>';
713 // propal => order
714 print '<tr><td colspan="2">'.checkLinkedElements('propal', 'commande')."</td></tr>\n";
715
716 // propal => invoice
717 print '<tr><td colspan="2">'.checkLinkedElements('propal', 'facture')."</td></tr>\n";
718
719 // order => invoice
720 print '<tr><td colspan="2">'.checkLinkedElements('commande', 'facture')."</td></tr>\n";
721
722 // order => shipping
723 print '<tr><td colspan="2">'.checkLinkedElements('commande', 'shipping')."</td></tr>\n";
724
725 // shipping => delivery
726 print '<tr><td colspan="2">'.checkLinkedElements('shipping', 'delivery')."</td></tr>\n";
727
728 // order_supplier => invoice_supplier
729 print '<tr><td colspan="2">'.checkLinkedElements('order_supplier', 'invoice_supplier')."</td></tr>\n";
730}
731
732
733// clean_menus: Check orphelins menus
734if ($ok && GETPOST('clean_menus', 'alpha')) {
735 print '<tr><td colspan="2"><br>*** Clean menu entries coming from disabled modules</td></tr>';
736
737 $sql = "SELECT rowid, module";
738 $sql .= " FROM ".MAIN_DB_PREFIX."menu as c";
739 $sql .= " WHERE module IS NOT NULL AND module <> ''";
740 $sql .= " ORDER BY module";
741
742 $resql = $db->query($sql);
743 if ($resql) {
744 $num = $db->num_rows($resql);
745 if ($num) {
746 $i = 0;
747 while ($i < $num) {
748 $obj = $db->fetch_object($resql);
749
750 $modulecond = $obj->module;
751 $modulecondarray = explode('|', $obj->module); // Name of module
752
753 print '<tr><td>';
754 print $modulecond;
755
756 $db->begin();
757
758 if ($modulecond) { // And menu entry for module $modulecond was found in database.
759 $moduleok = 0;
760 foreach ($modulecondarray as $tmpname) {
761 if ($tmpname == 'margins') {
762 $tmpname = 'margin'; // TODO Remove this when normalized
763 }
764
765 $result = 0;
766 if (!empty($conf->$tmpname)) {
767 $result = $conf->$tmpname->enabled;
768 }
769 if ($result) {
770 $moduleok++;
771 }
772 }
773
774 if (!$moduleok && $modulecond) {
775 print ' - Module condition '.$modulecond.' seems ko, we delete menu entry.';
776 if (GETPOST('clean_menus') == 'confirmed') {
777 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."menu WHERE module = '".$db->escape($modulecond)."'";
778 $resql2 = $db->query($sql2);
779 if (!$resql2) {
780 $error++;
781 dol_print_error($db);
782 } else {
783 print ' - <span class="warning">Cleaned</span>';
784 }
785 } else {
786 print ' - <span class="warning">Canceled (test mode)</span>';
787 }
788 } else {
789 print ' - Module condition '.$modulecond.' is ok, we do nothing.';
790 }
791 }
792
793 if (!$error) {
794 $db->commit();
795 } else {
796 $db->rollback();
797 }
798
799 print'</td></tr>';
800
801 if ($error) {
802 break;
803 }
804
805 $i++;
806 }
807 } else {
808 print '<tr><td>No menu entries of disabled menus found</td></tr>';
809 }
810 } else {
811 dol_print_error($db);
812 }
813}
814
815
816
817// clean_orphelin_dir: Run purge of directory
818if ($ok && GETPOST('clean_orphelin_dir', 'alpha')) {
819 $listmodulepart = array('company', 'invoice', 'invoice_supplier', 'propal', 'order', 'order_supplier', 'contract', 'tax');
820 foreach ($listmodulepart as $modulepart) {
821 $filearray = array();
822 $upload_dir = isset($conf->$modulepart->dir_output) ? $conf->$modulepart->dir_output : '';
823 if ($modulepart == 'company') {
824 $upload_dir = $conf->societe->dir_output; // TODO change for multicompany sharing
825 }
826 if ($modulepart == 'invoice') {
827 $upload_dir = $conf->facture->dir_output;
828 }
829 if ($modulepart == 'invoice_supplier') {
830 $upload_dir = $conf->fournisseur->facture->dir_output;
831 }
832 if ($modulepart == 'order') {
833 $upload_dir = $conf->commande->dir_output;
834 }
835 if ($modulepart == 'order_supplier') {
836 $upload_dir = $conf->fournisseur->commande->dir_output;
837 }
838 if ($modulepart == 'contract') {
839 $upload_dir = $conf->contrat->dir_output;
840 }
841
842 if (empty($upload_dir)) {
843 continue;
844 }
845
846 print '<tr><td colspan="2"><br>*** Clean orphelins files into files '.$upload_dir.'</td></tr>';
847
848 $filearray = dol_dir_list($upload_dir, "files", 1, '', array('^SPECIMEN\.pdf$', '^\.', '(\.meta|_preview.*\.png)$', '^temp$', '^payments$', '^CVS$', '^thumbs$'), '', SORT_DESC, 1, 1);
849
850 // To show ref or specific information according to view to show (defined by $module)
851 if ($modulepart == 'company') {
852 include_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
853 $object_instance = new Societe($db);
854 }
855 if ($modulepart == 'invoice') {
856 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
857 $object_instance = new Facture($db);
858 } elseif ($modulepart == 'invoice_supplier') {
859 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
860 $object_instance = new FactureFournisseur($db);
861 } elseif ($modulepart == 'propal') {
862 include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
863 $object_instance = new Propal($db);
864 } elseif ($modulepart == 'order') {
865 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
866 $object_instance = new Commande($db);
867 } elseif ($modulepart == 'order_supplier') {
868 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
869 $object_instance = new CommandeFournisseur($db);
870 } elseif ($modulepart == 'contract') {
871 include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
872 $object_instance = new Contrat($db);
873 } elseif ($modulepart == 'tax') {
874 include_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php';
875 $object_instance = new ChargeSociales($db);
876 }
877
878 foreach ($filearray as $key => $file) {
879 if (!is_dir($file['name'])
880 && $file['name'] != '.'
881 && $file['name'] != '..'
882 && $file['name'] != 'CVS'
883 ) {
884 // Define relative path used to store the file
885 $relativefile = preg_replace('/'.preg_quote($upload_dir.'/', '/').'/', '', $file['fullname']);
886
887 //var_dump($file);
888 $id = 0;
889 $ref = '';
890 $object_instance->id = 0;
891 $object_instance->ref = '';
892 $label = '';
893
894 // To show ref or specific information according to view to show (defined by $module)
895 if ($modulepart == 'invoice') {
896 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
897 $ref = $reg[1];
898 }
899 if ($modulepart == 'invoice_supplier') {
900 preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg);
901 $id = empty($reg[1]) ? '' : $reg[1];
902 }
903 if ($modulepart == 'propal') {
904 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
905 $ref = $reg[1];
906 }
907 if ($modulepart == 'order') {
908 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
909 $ref = $reg[1];
910 }
911 if ($modulepart == 'order_supplier') {
912 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
913 $ref = $reg[1];
914 }
915 if ($modulepart == 'contract') {
916 preg_match('/(.*)\/[^\/]+$/', $relativefile, $reg);
917 $ref = $reg[1];
918 }
919 if ($modulepart == 'tax') {
920 preg_match('/(\d+)\/[^\/]+$/', $relativefile, $reg);
921 $id = $reg[1];
922 }
923
924 if ($id || $ref) {
925 //print 'Fetch '.$id.' or '.$ref.'<br>';
926 $result = $object_instance->fetch($id, $ref);
927 //print $result.'<br>';
928 if ($result == 0) { // Not found but no error
929 // Clean of orphelins directories are done into repair.php
930 print '<tr><td colspan="2">';
931 print 'Delete orphelins file '.$file['fullname'].'<br>';
932 if (GETPOST('clean_orphelin_dir', 'alpha') == 'confirmed') {
933 dol_delete_file($file['fullname'], 1, 1, 1);
934 dol_delete_dir(dirname($file['fullname']), 1);
935 }
936 print "</td></tr>";
937 } elseif ($result < 0) {
938 print 'Error in '.get_class($object_instance).'.fetch of id'.$id.' ref='.$ref.', result='.$result.'<br>';
939 }
940 }
941 }
942 }
943 }
944}
945
946// clean_linked_elements: Check and clean linked elements
947if ($ok && GETPOST('clean_product_stock_batch', 'alpha')) {
948 $methodtofix = GETPOST('methodtofix', 'alpha') ? GETPOST('methodtofix', 'alpha') : 'updatestock';
949
950 print '<tr><td colspan="2"><br>*** Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
951
952 $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
953 $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";
954 $sql .= " WHERE p.rowid = ps.fk_product";
955 $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
956 $sql .= " HAVING (SUM(pb.qty) IS NOT NULL AND reel != SUM(pb.qty)) OR (SUM(pb.qty) IS NULL AND p.tobatch > 0)";
957 print $sql;
958 $resql = $db->query($sql);
959 if ($resql) {
960 $num = $db->num_rows($resql);
961
962 if ($num) {
963 $i = 0;
964 while ($i < $num) {
965 $obj = $db->fetch_object($resql);
966 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)';
967
968 // Fix is required
969 if ($obj->reel != $obj->reelbatch) {
970 if (empty($obj->tobatch)) {
971 // If product is not a product that support batches, we can clean stock by deleting the product batch lines
972 print ' -> Delete qty '.$obj->reelbatch.' for any lot linked to fk_product_stock='.$obj->psrowid;
973 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."product_batch";
974 $sql2 .= " WHERE fk_product_stock = ".((int) $obj->psrowid);
975 print '<br>'.$sql2;
976
977 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
978 $resql2 = $db->query($sql2);
979 if (!$resql2) {
980 $error++;
981 dol_print_error($db);
982 }
983 }
984 } else {
985 if ($methodtofix == 'updatebatch') {
986 // Method 1
987 print ' -> Insert qty '.($obj->reel - $obj->reelbatch).' with lot 000000 linked to fk_product_stock='.$obj->psrowid;
988 $sql2 = "INSERT INTO ".MAIN_DB_PREFIX."product_batch(fk_product_stock, batch, qty)";
989 $sql2 .= "VALUES(".((int) $obj->psrowid).", '000000', ".((float) ($obj->reel - $obj->reelbatch)).")";
990 print '<br>'.$sql2;
991
992 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
993 $resql2 = $db->query($sql2);
994 if (!$resql2) {
995 // TODO If it fails, we must make update
996 //$sql2 ="UPDATE ".MAIN_DB_PREFIX."product_batch";
997 //$sql2.=" SET ".$obj->psrowid.", '000000', ".($obj->reel - $obj->reelbatch).")";
998 //$sql2.=" WHERE fk_product_stock = ".((int) $obj->psrowid)
999 }
1000 }
1001 }
1002 if ($methodtofix == 'updatestock') {
1003 // Method 2
1004 print ' -> Update qty of product_stock with qty = '.($obj->reelbatch ? ((float) $obj->reelbatch) : '0').' for ps.rowid = '.((int) $obj->psrowid);
1005 $sql2 = "UPDATE ".MAIN_DB_PREFIX."product_stock";
1006 $sql2 .= " SET reel = ".($obj->reelbatch ? ((float) $obj->reelbatch) : '0')." WHERE rowid = ".((int) $obj->psrowid);
1007 print '<br>'.$sql2;
1008
1009 if (GETPOST('clean_product_stock_batch') == 'confirmed') {
1010 $error = 0;
1011
1012 $db->begin();
1013
1014 $resql2 = $db->query($sql2);
1015 if ($resql2) {
1016 // We update product_stock, so we must fill p.stock into product too.
1017 $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)';
1018 $resql3 = $db->query($sql3);
1019 if (!$resql3) {
1020 $error++;
1021 dol_print_error($db);
1022 }
1023 } else {
1024 $error++;
1025 dol_print_error($db);
1026 }
1027
1028 if (!$error) {
1029 $db->commit();
1030 } else {
1031 $db->rollback();
1032 }
1033 }
1034 }
1035 }
1036 }
1037
1038 print'</td></tr>';
1039
1040 $i++;
1041 }
1042 } else {
1043 print '<tr><td colspan="2">Nothing to do</td></tr>';
1044 }
1045 } else {
1046 dol_print_error($db);
1047 }
1048}
1049
1050
1051// clean_product_stock_negative_if_batch
1052if ($ok && GETPOST('clean_product_stock_negative_if_batch', 'alpha')) {
1053 print '<tr><td colspan="2"><br>Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
1054
1055 $sql = "SELECT p.rowid, p.ref, p.tobatch, ps.rowid as psrowid, ps.fk_entrepot, ps.reel, SUM(pb.qty) as reelbatch";
1056 $sql .= " FROM ".MAIN_DB_PREFIX."product as p, ".MAIN_DB_PREFIX."product_stock as ps, ".MAIN_DB_PREFIX."product_batch as pb";
1057 $sql .= " WHERE p.rowid = ps.fk_product AND ps.rowid = pb.fk_product_stock";
1058 $sql .= " AND p.tobatch > 0";
1059 $sql .= " GROUP BY p.rowid, p.ref, p.tobatch, ps.rowid, ps.fk_entrepot, ps.reel";
1060 $sql .= " HAVING reel != SUM(pb.qty)";
1061 $resql = $db->query($sql);
1062 if ($resql) {
1063 $num = $db->num_rows($resql);
1064
1065 if ($num) {
1066 $i = 0;
1067 while ($i < $num) {
1068 $obj = $db->fetch_object($resql);
1069 print '<tr><td>'.$obj->rowid.'-'.$obj->ref.'-'.$obj->fk_entrepot.' -> '.$obj->psrowid.': '.$obj->reel.' != '.$obj->reelbatch;
1070
1071 // TODO
1072 }
1073 }
1074 }
1075}
1076
1077// set_empty_time_spent_amount
1078if ($ok && GETPOST('set_empty_time_spent_amount', 'alpha')) {
1079 print '<tr><td colspan="2"><br>*** Set value of time spent without amount</td></tr>';
1080
1081 $sql = "SELECT COUNT(ptt.rowid) as nb, u.rowid as user_id, u.login, u.thm as user_thm";
1082 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as ptt, ".MAIN_DB_PREFIX."user as u";
1083 $sql .= " WHERE ptt.fk_user = u.rowid";
1084 $sql .= " AND ptt.thm IS NULL and u.thm > 0";
1085 $sql .= " GROUP BY u.rowid, u.login, u.thm";
1086
1087 $resql = $db->query($sql);
1088 if ($resql) {
1089 $num = $db->num_rows($resql);
1090
1091 if ($num) {
1092 $i = 0;
1093 while ($i < $num) {
1094 $obj = $db->fetch_object($resql);
1095 print '<tr><td>'.$obj->login.'-'.$obj->user_id.' ('.$obj->nb.' lines to fix) -> '.$obj->user_thm;
1096
1097 $db->begin();
1098
1099 if (GETPOST('set_empty_time_spent_amount') == 'confirmed') {
1100 $sql2 = "UPDATE ".MAIN_DB_PREFIX."element_time";
1101 $sql2 .= " SET thm = ".$obj->user_thm." WHERE thm IS NULL AND fk_user = ".((int) $obj->user_id);
1102 $resql2 = $db->query($sql2);
1103 if (!$resql2) {
1104 $error++;
1105 dol_print_error($db);
1106 }
1107 }
1108
1109 if (!$error) {
1110 $db->commit();
1111 } else {
1112 $db->rollback();
1113 }
1114
1115 print'</td></tr>';
1116
1117 if ($error) {
1118 break;
1119 }
1120
1121 $i++;
1122 }
1123 } else {
1124 print '<tr><td>No time spent with empty line on users with a hourly rate defined</td></tr>';
1125 }
1126 } else {
1127 dol_print_error($db);
1128 }
1129}
1130
1131
1132// force_disable_of_modules_not_found
1133if ($ok && GETPOST('force_disable_of_modules_not_found', 'alpha')) {
1134 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>';
1135
1136 $arraylistofkey = array('hooks', 'js', 'css');
1137
1138 foreach ($arraylistofkey as $key) {
1139 $sql = "SELECT DISTINCT name, value";
1140 $sql .= " FROM ".MAIN_DB_PREFIX."const as c";
1141 $sql .= " WHERE name LIKE 'MAIN_MODULE_%_".strtoupper($key)."'";
1142 $sql .= " ORDER BY name";
1143
1144 $resql = $db->query($sql);
1145 if ($resql) {
1146 $num = $db->num_rows($resql);
1147 if ($num) {
1148 $i = 0;
1149 while ($i < $num) {
1150 $obj = $db->fetch_object($resql);
1151 $constantname = $obj->name; // Name of constant for hook or js or css declaration
1152
1153 print '<tr><td>';
1154 print dol_escape_htmltag($constantname);
1155
1156 $db->begin();
1157
1158 $reg = array();
1159 if (preg_match('/MAIN_MODULE_(.*)_'.strtoupper($key).'/i', $constantname, $reg)) {
1160 $name = strtolower($reg[1]);
1161
1162 if ($name) { // An entry for key $key and module $name was found in database.
1163 $reloffile = '';
1164 $result = 'found';
1165
1166 if ($key == 'hooks') {
1167 $reloffile = $name.'/class/actions_'.$name.'.class.php';
1168 }
1169 if ($key == 'js') {
1170 $value = $obj->value;
1171 $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1172 $reloffile = $valuearray[0];
1173 $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1174 }
1175 if ($key == 'css') {
1176 $value = $obj->value;
1177 $valuearray = (array) json_decode($value); // Force cast into array because sometimes it is a stdClass
1178 if ($value && (!is_array($valuearray) || count($valuearray) == 0)) {
1179 $valuearray = array();
1180 $valuearray[0] = $value; // If value was not a json array but a string
1181 }
1182 $reloffile = preg_replace('/^\//', '', $valuearray[0]);
1183 }
1184
1185 if ($reloffile) {
1186 //var_dump($key.' - '.$value.' - '.$reloffile);
1187 try {
1188 $result = dol_buildpath($reloffile, 0, 2);
1189 } catch (Exception $e) {
1190 $result = 'found'; // If error, we force like if we found to avoid any deletion
1191 }
1192 } else {
1193 $result = 'found'; //
1194 }
1195
1196 if (!$result) {
1197 print ' - File of '.$key.' ('.$reloffile.') NOT found, we disable the module.';
1198 if (GETPOST('force_disable_of_modules_not_found') == 'confirmed') {
1199 $sql2 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."_".strtoupper($key)."'";
1200 $resql2 = $db->query($sql2);
1201 if (!$resql2) {
1202 $error++;
1203 dol_print_error($db);
1204 }
1205 $sql3 = "DELETE FROM ".MAIN_DB_PREFIX."const WHERE name = 'MAIN_MODULE_".strtoupper($name)."'";
1206 $resql3 = $db->query($sql3);
1207 if (!$resql3) {
1208 $error++;
1209 dol_print_error($db);
1210 } else {
1211 print ' - <span class="warning">Cleaned</span>';
1212 }
1213 } else {
1214 print ' - <span class="warning">Canceled (test mode)</span>';
1215 }
1216 } else {
1217 print ' - File of '.$key.' ('.$reloffile.') found, we do nothing.';
1218 }
1219 }
1220
1221 if (!$error) {
1222 $db->commit();
1223 } else {
1224 $db->rollback();
1225 }
1226 }
1227
1228 print'</td></tr>';
1229
1230 if ($error) {
1231 break;
1232 }
1233
1234 $i++;
1235 }
1236 } else {
1237 print '<tr><td>No active module with missing files found by searching on MAIN_MODULE_(.*)_'.strtoupper($key).'</td></tr>';
1238 }
1239 } else {
1240 dol_print_error($db);
1241 }
1242 }
1243}
1244
1245
1246// clean_old_module_entries: Clean data into const when files of module were removed without being
1247if ($ok && GETPOST('clean_perm_table', 'alpha')) {
1248 print '<tr><td colspan="2"><br>*** Clean table user_rights from lines of external modules no more enabled</td></tr>';
1249
1250 $listofmods = '';
1251 foreach ($conf->modules as $key => $val) {
1252 $listofmods .= ($listofmods ? ',' : '')."'".$db->escape($val)."'";
1253 }
1254
1255 $sql = "SELECT id, libelle as label, module from ".MAIN_DB_PREFIX."rights_def WHERE module NOT IN (".$db->sanitize($listofmods, 1).") AND id > 100000";
1256
1257 $resql = $db->query($sql);
1258 if ($resql) {
1259 $num = $db->num_rows($resql);
1260 if ($num) {
1261 $i = 0;
1262 while ($i < $num) {
1263 $obj = $db->fetch_object($resql);
1264 if ($obj->id > 0) {
1265 print '<tr><td>Found line with id '.$obj->id.', label "'.$obj->label.'" of module "'.$obj->module.'" to delete';
1266 if (GETPOST('clean_perm_table', 'alpha') == 'confirmed') {
1267 $sqldelete = "DELETE FROM ".MAIN_DB_PREFIX."rights_def WHERE id = ".((int) $obj->id);
1268 $resqldelete = $db->query($sqldelete);
1269 if (!$resqldelete) {
1270 dol_print_error($db);
1271 }
1272 print ' - deleted';
1273 }
1274 print '</td></tr>';
1275 }
1276 $i++;
1277 }
1278 } else {
1279 print '<tr><td>No lines of a disabled external module (with id > 100000) found into table rights_def</td></tr>';
1280 }
1281 } else {
1282 dol_print_error($db);
1283 }
1284}
1285
1286
1287
1288// force utf8 on tables
1289if ($ok && GETPOST('force_utf8_on_tables', 'alpha')) {
1290 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>';
1291
1292 if ($db->type == "mysql" || $db->type == "mysqli") {
1293 $force_utf8_on_tables = GETPOST('force_utf8_on_tables', 'alpha');
1294
1295 $listoftables = $db->DDLListTablesFull($db->database_name);
1296
1297 // Disable foreign key checking for avoid errors
1298 if ($force_utf8_on_tables == 'confirmed') {
1299 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1300 print '<!-- '.$sql.' -->';
1301 $resql = $db->query($sql);
1302 }
1303
1304 foreach ($listoftables as $table) {
1305 // do not convert llx_const if mysql encrypt/decrypt is used
1306 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1307 continue;
1308 }
1309 if ($table[1] == 'VIEW') {
1310 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1311 continue;
1312 }
1313
1314 print '<tr><td colspan="2">';
1315 print $table[0];
1316 $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1317 $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci";
1318 print '<!-- '.$sql1.' -->';
1319 print '<!-- '.$sql2.' -->';
1320 if ($force_utf8_on_tables == 'confirmed') {
1321 $resql1 = $db->query($sql1);
1322 if ($resql1) {
1323 $resql2 = $db->query($sql2);
1324 } else {
1325 $resql2 = false;
1326 }
1327 print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
1328 } else {
1329 print ' - Disabled';
1330 }
1331 print '</td></tr>';
1332 }
1333
1334 // Enable foreign key checking
1335 if ($force_utf8_on_tables == 'confirmed') {
1336 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1337 print '<!-- '.$sql.' -->';
1338 $resql = $db->query($sql);
1339 }
1340 } else {
1341 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1342 }
1343}
1344
1345// force utf8mb4 on tables EXPERIMENTAL !
1346if ($ok && GETPOST('force_utf8mb4_on_tables', 'alpha')) {
1347 print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8mb4/utf8mb4_unicode_ci (for mysql/mariadb only)</td></tr>';
1348
1349 if ($db->type == "mysql" || $db->type == "mysqli") {
1350 $force_utf8mb4_on_tables = GETPOST('force_utf8mb4_on_tables', 'alpha');
1351
1352 $listoftables = $db->DDLListTablesFull($db->database_name);
1353
1354 // Disable foreign key checking for avoid errors
1355 if ($force_utf8mb4_on_tables == 'confirmed') {
1356 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1357 print '<!-- '.$sql.' -->';
1358 $resql = $db->query($sql);
1359 }
1360
1361 foreach ($listoftables as $table) {
1362 // do not convert llx_const if mysql encrypt/decrypt is used
1363 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1364 continue;
1365 }
1366 if ($table[1] == 'VIEW') {
1367 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1368 continue;
1369 }
1370
1371 print '<tr><td colspan="2">';
1372 print $table[0];
1373 $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1374 $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
1375 print '<!-- '.$sql1.' -->';
1376 print '<!-- '.$sql2.' -->';
1377 if ($force_utf8mb4_on_tables == 'confirmed') {
1378 $resql1 = $db->query($sql1);
1379 if ($resql1) {
1380 $resql2 = $db->query($sql2);
1381 } else {
1382 $resql2 = false;
1383 }
1384 print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
1385 } else {
1386 print ' - Disabled';
1387 }
1388 print '</td></tr>';
1389 flush();
1390 ob_flush();
1391 }
1392
1393 // Enable foreign key checking
1394 if ($force_utf8mb4_on_tables == 'confirmed') {
1395 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1396 print '<!-- '.$sql.' -->';
1397 $resql = $db->query($sql);
1398 }
1399 } else {
1400 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1401 }
1402}
1403
1404if ($ok && GETPOST('force_collation_from_conf_on_tables', 'alpha')) {
1405 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>';
1406
1407 if ($db->type == "mysql" || $db->type == "mysqli") {
1408 $force_collation_from_conf_on_tables = GETPOST('force_collation_from_conf_on_tables', 'alpha');
1409
1410 $listoftables = $db->DDLListTablesFull($db->database_name);
1411
1412 // Disable foreign key checking for avoid errors
1413 if ($force_collation_from_conf_on_tables == 'confirmed') {
1414 $sql = 'SET FOREIGN_KEY_CHECKS=0';
1415 print '<!-- '.$sql.' -->';
1416 $resql = $db->query($sql);
1417 }
1418
1419 foreach ($listoftables as $table) {
1420 // do not convert collation on llx_const if mysql encrypt/decrypt is used
1421 if ($conf->db->dolibarr_main_db_encryption != 0 && preg_match('/\_const$/', $table[0])) {
1422 continue;
1423 }
1424 if ($table[1] == 'VIEW') {
1425 print '<tr><td colspan="2">'.$table[0].' is a '.$table[1].' (Skipped)</td></tr>';
1426 continue;
1427 }
1428
1429 print '<tr><td colspan="2">';
1430 print $table[0];
1431 $sql1 = "ALTER TABLE ".$table[0]." ROW_FORMAT=dynamic";
1432 $sql2 = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET ".$conf->db->character_set." COLLATE ".$conf->db->dolibarr_main_db_collation;
1433 print '<!-- '.$sql1.' -->';
1434 print '<!-- '.$sql2.' -->';
1435 if ($force_collation_from_conf_on_tables == 'confirmed') {
1436 $resql1 = $db->query($sql1);
1437 if ($resql1) {
1438 $resql2 = $db->query($sql2);
1439 } else {
1440 $resql2 = false;
1441 }
1442 print ' - Done ('.(($resql1 && $resql2) ? 'OK' : 'KO').')';
1443 } else {
1444 print ' - Disabled';
1445 }
1446 print '</td></tr>';
1447 }
1448
1449 // Enable foreign key checking
1450 if ($force_collation_from_conf_on_tables == 'confirmed') {
1451 $sql = 'SET FOREIGN_KEY_CHECKS=1';
1452 print '<!-- '.$sql.' -->';
1453 $resql = $db->query($sql);
1454 }
1455 } else {
1456 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1457 }
1458}
1459
1460// rebuild sequences for pgsql
1461if ($ok && GETPOST('rebuild_sequences', 'alpha')) {
1462 print '<tr><td colspan="2"><br>*** Force to rebuild sequences (for postgresql only)</td></tr>';
1463
1464 if ($db->type == "pgsql") {
1465 $rebuild_sequence = GETPOST('rebuild_sequences', 'alpha');
1466
1467 if ($rebuild_sequence == 'confirmed') {
1468 $sql = "SELECT dol_util_rebuild_sequences();";
1469 print '<!-- '.$sql.' -->';
1470 $resql = $db->query($sql);
1471 }
1472 } else {
1473 print '<tr><td colspan="2">Not available with database type '.$db->type.'</td></tr>';
1474 }
1475}
1476
1477//
1478if ($ok && GETPOST('repair_link_dispatch_lines_supplier_order_lines')) {
1479 /*
1480 * This script is meant to be run when upgrading from a dolibarr version < 3.8
1481 * to a newer version.
1482 *
1483 * Version 3.8 introduces a new column in llx_commande_fournisseur_dispatch, which
1484 * matches the dispatch to a specific supplier order line (so that if there are
1485 * several with the same product, the user can specifically tell which products of
1486 * which line were dispatched where).
1487 *
1488 * However when migrating, the new column has a default value of 0, which means that
1489 * old supplier orders whose lines were dispatched using the old dolibarr version
1490 * have unspecific dispatch lines, which are not taken into account by the new version,
1491 * thus making the order look like it was never dispatched at all.
1492 *
1493 * This scripts sets this foreign key to the first matching supplier order line whose
1494 * product (and supplier order of course) are the same as the dispatch’s.
1495 *
1496 * If the dispatched quantity is more than indicated on the order line (this happens if
1497 * there are several order lines for the same product), it creates new dispatch lines
1498 * pointing to the other order lines accordingly, until all the dispatched quantity is
1499 * accounted for.
1500 */
1501
1502 $repair_link_dispatch_lines_supplier_order_lines = GETPOST('repair_link_dispatch_lines_supplier_order_lines', 'alpha');
1503
1504
1505 echo '<tr><th>Repair llx_receptiondet_batch.fk_commandefourndet</th></tr>';
1506 echo '<tr><td>Repair in progress. This may take a while.</td></tr>';
1507
1508 $sql_dispatch = 'SELECT * FROM '.MAIN_DB_PREFIX.'receptiondet_batch WHERE COALESCE(fk_elementdet, 0) = 0';
1509 $db->begin();
1510 $resql_dispatch = $db->query($sql_dispatch);
1511 $n_processed_rows = 0;
1512 $errors = array();
1513 if ($resql_dispatch) {
1514 if ($db->num_rows($resql_dispatch) == 0) {
1515 echo '<tr><td>Nothing to do.</td></tr>';
1516 exit;
1517 }
1518 while ($obj_dispatch = $db->fetch_object($resql_dispatch)) {
1519 $sql_line = 'SELECT line.rowid, line.qty FROM '.MAIN_DB_PREFIX.'commande_fournisseurdet AS line';
1520 $sql_line .= ' WHERE line.fk_commande = '.((int) $obj_dispatch->fk_commande);
1521 $sql_line .= ' AND line.fk_product = '.((int) $obj_dispatch->fk_product);
1522 $resql_line = $db->query($sql_line);
1523
1524 // s’il y a plusieurs lignes avec le même produit sur cette commande fournisseur,
1525 // on divise la ligne de dispatch en autant de lignes qu’on en a sur la commande pour le produit
1526 // et on met la quantité de la ligne dans la limit du "budget" indiqué par dispatch.qty
1527
1528 $remaining_qty = $obj_dispatch->qty;
1529 $first_iteration = true;
1530 if (!$resql_line) {
1531 echo '<tr><td>Unable to find a matching supplier order line for dispatch #'.$obj_dispatch->rowid.'</td></tr>';
1532 $errors[] = $sql_line;
1533 $n_processed_rows++;
1534 continue;
1535 }
1536 if ($db->num_rows($resql_line) == 0) {
1537 continue;
1538 }
1539 while ($obj_line = $db->fetch_object($resql_line)) {
1540 if (!$remaining_qty) {
1541 break;
1542 }
1543 if (!$obj_line->rowid) {
1544 continue;
1545 }
1546 $qty_for_line = min($remaining_qty, $obj_line->qty);
1547 if ($first_iteration) {
1548 $sql_attach = 'UPDATE '.MAIN_DB_PREFIX.'receptiondet_batch';
1549 $sql_attach .= ' SET fk_elementdet = '.((int) $obj_line->rowid).', qty = '.((float) $qty_for_line);
1550 $sql_attach .= ' WHERE rowid = '.((int) $obj_dispatch->rowid);
1551 $first_iteration = false;
1552 } else {
1553 $sql_attach_values = array(
1554 (string) ((int) $obj_dispatch->fk_element),
1555 (string) ((int) $obj_dispatch->fk_product),
1556 (string) ((int) $obj_line->rowid),
1557 (string) ((float) $qty_for_line),
1558 (string) ((int) $obj_dispatch->fk_entrepot),
1559 (string) ((int) $obj_dispatch->fk_user),
1560 $obj_dispatch->datec ? "'".$db->idate($db->jdate($obj_dispatch->datec))."'" : 'NULL',
1561 $obj_dispatch->comment ? "'".$db->escape($obj_dispatch->comment)."'" : 'NULL',
1562 $obj_dispatch->status ? (string) ((int) $obj_dispatch->status) : 'NULL',
1563 $obj_dispatch->tms ? "'".$db->idate($db->jdate($obj_dispatch->tms))."'" : 'NULL',
1564 $obj_dispatch->batch ? "'".$db->escape($obj_dispatch->batch)."'" : 'NULL',
1565 $obj_dispatch->eatby ? "'".$db->escape($obj_dispatch->eatby)."'" : 'NULL',
1566 $obj_dispatch->sellby ? "'".$db->escape($obj_dispatch->sellby)."'" : 'NULL'
1567 );
1568 $sql_attach_values = implode(', ', $sql_attach_values);
1569
1570 $sql_attach = 'INSERT INTO '.MAIN_DB_PREFIX.'receptiondet_batch';
1571 $sql_attach .= ' (fk_element, fk_product, fk_elementdet, qty, fk_entrepot, fk_user, datec, comment, status, tms, batch, eatby, sellby)';
1572 $sql_attach .= " VALUES (".$sql_attach_values.")"; // The string is already sanitized
1573 }
1574
1575 if ($repair_link_dispatch_lines_supplier_order_lines == 'confirmed') {
1576 $resql_attach = $db->query($sql_attach);
1577 } else {
1578 $resql_attach = true; // Force success in test mode
1579 }
1580
1581 if ($resql_attach) {
1582 $remaining_qty -= $qty_for_line;
1583 } else {
1584 $errors[] = $sql_attach;
1585 }
1586
1587 $first_iteration = false;
1588 }
1589 $n_processed_rows++;
1590
1591 // report progress every 256th row
1592 if (!($n_processed_rows & 0xff)) {
1593 echo '<tr><td>Processed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1594 flush();
1595 ob_flush();
1596 }
1597 }
1598 } else {
1599 echo '<tr><td>Unable to find any dispatch without an fk_commandefourndet.'."</td></tr>\n";
1600 echo $sql_dispatch."\n";
1601 }
1602 echo '<tr><td>Fixed '.$n_processed_rows.' rows with '.count($errors).' errors…'."</td></tr>\n";
1603 echo '<tr><td>DONE.'."</td></tr>\n";
1604
1605 if (count($errors)) {
1606 $db->rollback();
1607 echo '<tr><td>The transaction was rolled back due to errors: nothing was changed by the script.</td></tr>';
1608 } else {
1609 $db->commit();
1610 }
1611 $db->close();
1612
1613 echo '<tr><td><h3>SQL queries with errors:</h3></tr></td>';
1614 echo '<tr><td>'.implode('</td></tr><tr><td>', $errors).'</td></tr>';
1615}
1616
1617// Repair llx_commande_fournisseur to eliminate duplicate reference
1618if ($ok && GETPOST('repair_supplier_order_duplicate_ref')) {
1619 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php';
1620 include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1621
1622 $db->begin();
1623
1624 $err = 0;
1625
1626 // Query to find all duplicate supplier orders
1627 $sql = "SELECT * FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
1628 $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)";
1629
1630 // Build a list of ref => []CommandeFournisseur
1631 $duplicateSupplierOrders = [];
1632 $resql = $db->query($sql);
1633 if ($resql) {
1634 while ($rawSupplierOrder = $db->fetch_object($resql)) {
1635 $supplierOrder = new CommandeFournisseur($db);
1636 $supplierOrder->setVarsFromFetchObj($rawSupplierOrder);
1637
1638 $duplicateSupplierOrders[$rawSupplierOrder->ref] [] = $supplierOrder;
1639 }
1640 } else {
1641 $err++;
1642 }
1643
1644 // Process all duplicate supplier order and regenerate the reference for all except the first one
1645 foreach ($duplicateSupplierOrders as $ref => $supplierOrders) {
1647 foreach (array_slice($supplierOrders, 1) as $supplierOrder) {
1648 // Definition of supplier order numbering model name
1649 $soc = new Societe($db);
1650 $soc->fetch($supplierOrder->fourn_id);
1651
1652 $newRef = $supplierOrder->getNextNumRef($soc);
1653
1654 $sql = "UPDATE " . MAIN_DB_PREFIX . "commande_fournisseur cf SET cf.ref = '" . $db->escape($newRef) . "' WHERE cf.rowid = " . (int) $supplierOrder->id;
1655 if (!$db->query($sql)) {
1656 $err++;
1657 }
1658 }
1659 }
1660
1661 if ($err == 0) {
1662 $db->commit();
1663 } else {
1664 $db->rollback();
1665 }
1666}
1667
1668// Repair llx_invoice to calculate totals from line items
1669// WARNING : The process can be long on production environments due to restrictions.
1670// consider raising php_max_execution time if failing to execute completely.
1671if ($ok && GETPOST('recalculateinvoicetotal') == 'confirmed') {
1672 $err = 0;
1673 $db->begin();
1674 $sql = "SELECT f.rowid, SUM(fd.total_ht) as total_ht";
1675 $sql .= " FROM ".MAIN_DB_PREFIX."facture f";
1676 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet fd ON fd.fk_facture = f.rowid";
1677 $sql .= " WHERE f.total_ht = 0";
1678 $sql .= " GROUP BY fd.fk_facture HAVING SUM(fd.total_ht) <> 0";
1679
1680 $resql = $db->query($sql);
1681 if ($resql) {
1682 $num = $db->num_rows($resql);
1683 print "We found ".$num." factures qualified that will have their total recalculated because they are at zero and line items not at zero\n";
1684 dol_syslog("We found ".$num." factures qualified that will have their total recalculated because they are at zero and line items not at zero");
1685
1686 if ($num) {
1687 $i = 0;
1688 while ($i < $num) {
1689 $obj = $db->fetch_object($resql);
1690 $sql_calculs = "
1691 SELECT
1692 SUM(fd.total_ht) as 'total_ht',
1693 SUM(fd.total_tva) as 'total_tva',
1694 SUM(fd.total_localtax1) as 'localtax1',
1695 SUM(fd.total_localtax2) as 'localtax2',
1696 SUM(fd.total_ttc) as 'total_ttc'
1697 FROM
1698 ".MAIN_DB_PREFIX."facturedet fd
1699 WHERE
1700 fd.fk_facture = $obj->rowid";
1701 $ressql_calculs = $db->query($sql_calculs);
1702 while ($obj_calcul = $db->fetch_object($ressql_calculs)) {
1703 $sql_maj = "
1704 UPDATE ".MAIN_DB_PREFIX."facture
1705 SET
1706 total_ht = ".($obj_calcul->total_ht ? price2num($obj_calcul->total_ht, 'MT') : 0).",
1707 total_tva = ".($obj_calcul->total_tva ? price2num($obj_calcul->total_tva, 'MT') : 0).",
1708 localtax1 = ".($obj_calcul->localtax1 ? price2num($obj_calcul->localtax1, 'MT') : 0).",
1709 localtax2 = ".($obj_calcul->localtax2 ? price2num($obj_calcul->localtax2, 'MT') : 0).",
1710 total_ttc = ".($obj_calcul->total_ttc ? price2num($obj_calcul->total_ttc, 'MT') : 0)."
1711 WHERE
1712 rowid = $obj->rowid";
1713 $db->query($sql_maj);
1714 }
1715 $i++;
1716 }
1717 } else {
1718 print "Pas de factures à traiter\n";
1719 }
1720 } else {
1721 dol_print_error($db);
1722 dol_syslog("calculate_total_and_taxes.php: Error");
1723 $err++;
1724 }
1725
1726 if ($err == 0) {
1727 $db->commit();
1728 } else {
1729 $db->rollback();
1730 }
1731}
1732
1733print '</table>';
1734
1735if (empty($actiondone)) {
1736 print '<div class="error">'.$langs->trans("ErrorWrongParameters").'</div>';
1737}
1738
1739if ($oneoptionset) {
1740 print '<div class="center" style="padding-top: 10px"><a href="../index.php?mainmenu=home&leftmenu=home'.(GETPOSTISSET("login") ? '&username='.urlencode(GETPOST("login")) : '').'">';
1741 print $langs->trans("GoToDolibarr");
1742 print '</a></div>';
1743}
1744
1745dolibarr_install_syslog("--- repair: end");
1746pFooter(1, $setuplang);
1747
1748if ($db->connected) {
1749 $db->close();
1750}
1751
1752// Return code if ran from command line
1753if (!$ok && isset($argv[1])) {
1754 exit(1);
1755}
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition security.php:626
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 contracts.
Class to manage standard extra fields.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
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:63
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...
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:535
pFooter($nonext=0, $setuplang='', $jscheckfunction='', $withpleasewait=0, $morehtml='')
Print HTML footer of install pages.
Definition inc.php:626
dolibarr_install_syslog($message, $level=LOG_DEBUG)
Log function for install pages.
Definition inc.php:690
clean_data_ecm_directories()
Clean data into ecm_directories table.
dol_decode($chain, $key='1')
Decode a base 64 encoded + specific delta change.