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