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