2 /**********************************************************************
3 Copyright (C) FrontAccounting, LLC.
4 Released under the terms of the GNU General Public License, GPL,
5 as published by the Free Software Foundation, either version 3
6 of the License, or (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
13 class fa2_4 extends fa_patch {
14 var $previous = '2.3rc'; // applicable database version
15 var $version = '2.4.1'; // version installed
17 var $sql = 'alter2.4.sql';
18 var $max_upgrade_time = 900; // table recoding is really long process
20 function __construct() {
21 parent::__construct();
22 $this->description = _('Upgrade from version 2.3 to 2.4');
26 Shows parameters to be selected before upgrade (if any)
28 function show_params($comp)
30 display_note(_('Set optimal parameters and start upgrade:'));
31 start_table(TABLESTYLE);
33 collations_list_row(_('Text collation optimization:'), 'collation', substr($_SESSION['language']->code, 0, 2));
40 Fetches selected upgrade parameters.
44 $this->collation = get_post('collation');
49 // Install procedure. All additional changes
50 // not included in sql file should go here.
52 function install($company, $force=false)
54 global $db_version, $db_connections;
56 $pref = $db_connections[$company]['tbpref'];
58 if (get_company_pref('grn_clearing_act') === null) { // available form 2.3.1, can be not defined on pre-2.4 installations
59 set_company_pref('grn_clearing_act', 'glsetup.purchase', 'varchar', 15, 0);
61 if (get_company_pref('default_quote_valid_days') === null) { // new in 2.3.23 installations
62 set_company_pref('default_quote_valid_days', 'glsetup.sales', 'smallint', 6, 30);
64 if (get_company_pref('bcc_email') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
65 set_company_pref('bcc_email', 'setup.company', 'varchar', 100, '');
67 if (get_company_pref('alternative_tax_include_on_docs') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
68 set_company_pref('alternative_tax_include_on_docs', 'setup.company', 'tinyint', 1, '0');
70 if (get_company_pref('suppress_tax_rates') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
71 set_company_pref('suppress_tax_rates', 'setup.company', 'tinyint', 1, '0');
73 if (get_company_pref('company_logo_report') === null) { // available from 2.4.2, during updates
74 set_company_pref('company_logo_report', 'setup.company', 'tinyint', 1, '0');
76 if (get_company_pref('print_dialog_direct') === null) { // available from 2.4.5, during updates
77 set_company_pref('print_dialog_direct', 'setup.company', 'tinyint', 1, '0');
79 if (get_company_pref('barcodes_on_stock') === null) { // available from 2.4.3, during updates
80 set_company_pref('barcodes_on_stock', 'setup.company', 'tinyint', 1, '0');
82 if (get_company_pref('ref_no_auto_increase') === null) { // available from 2.4.4, during updates
83 set_company_pref('ref_no_auto_increase', 'setup.company', 'tinyint', 1, '0');
85 if (get_company_pref('shortname_name_in_list') === null) { // available from 2.4.2, during updates
86 set_company_pref('shortname_name_in_list', 'setup.company', 'tinyint', 1, '0');
89 $result = $this->update_workorders() && $this->update_grn_rates() && $this->switch_database_to_utf($pref);
92 $result = $this->do_cleanup();
95 $db_connections[$company]['collation'] = $this->collation;
96 if (write_config_db())
97 return $this->log_error(_("Cannot update config_db.php file."));
100 $sec_updates = array(
101 'SA_SETUPCOMPANY' => array(
102 'SA_ASSET', 'SA_ASSETCATEGORY', 'SA_ASSETCLASS',
103 'SA_ASSETSTRANSVIEW','SA_ASSETTRANSFER', 'SA_ASSETDISPOSAL',
104 'SA_DEPRECIATION', 'SA_ASSETSANALYTIC'),
106 $result = $this->update_security_roles($sec_updates);
112 // optional procedure done after upgrade fail, before backup is restored
114 function post_fail($company)
116 $pref = $this->companies[$company]['tbpref'];
117 db_query("DROP TABLE IF EXISTS " . $pref . 'wo_costing');
118 db_query("DROP TABLE IF EXISTS " . $pref . 'stock_fa_class');
119 db_query("DELETE FROM ".$pref."sys_prefs
121 'gl_closing_date', 'deferred_income_act', 'no_zero_lines_amount', 'accounts_alpha',
122 'tax_algorithm', 'grn_clearing_act', 'default_receival_required',
123 'default_quote_valid_days', 'no_zero_lines_amount', 'show_po_item_codes', 'accounts_alpha',
124 'loc_notification', 'print_invoice_no', 'allow_negative_prices', 'print_item_images_on_quote',
125 'bcc_email', 'alternative_tax_include_on_docs', 'suppress_tax_rates', 'company_logo_report',
126 'barcodes_on_stock', print_dialog_direct', 'ref_no_auto_increase')");
129 function update_workorders()
133 $sql = "SELECT DISTINCT type, type_no, tran_date, person_id FROM ".TB_PREF."gl_trans WHERE `type`=".ST_WORKORDER
134 ." AND person_type_id=1";
135 $res = db_query($sql);
137 return $this->log_error(sprintf(_("Cannot update work orders costs:\n%s"), db_error_msg($db)));
139 while ($row = db_fetch($res))
141 $journal_id = get_next_trans_no(ST_JOURNAL);
143 $sql1 = "UPDATE ".TB_PREF."gl_trans SET `type`=".ST_JOURNAL.", type_no={$journal_id},
144 person_type_id=NULL, person_id=0
145 WHERE `type`=".ST_WORKORDER." AND type_no={$row['type_no']} AND tran_date='{$row['tran_date']}'
146 AND person_id='{$row['person_id']}'";
147 if (!db_query($sql1)) return false;
149 $sql2 = "INSERT INTO ".TB_PREF."wo_costing (workorder_id, cost_type, trans_no)
150 VALUES ({$row['type_no']}, {$row['person_id']}, {$journal_id})";
151 if (!db_query($sql2)) return false;
157 In previous versions FA ignored encoding settings on database/tables, so it depended on server settings,
158 but data stored is encoded in user language encoding. Now we switch to utf8 internal database encoding, while
159 user encoding can be selected independently.
161 To perform safe FA database switch to utf-8 encoding we have to first ensure that all text/char columns
162 have properly set encoding (the same as its content), so the algorithm performed on every table is as follows:
163 . set default table encoding for the table to currently used on client side;
164 . for all text/char column:
165 - suppress autorecoding by change of the type to related binary/blob type
166 - change column to utf8 encodding and selected collation.
167 . change default table encoding to utf8 and selected collation
169 function switch_database_to_utf($pref, $dbg = false) {
171 global $installed_languages, $dflt_lang;
173 $old_encoding = 'latin1'; // default client encoding
175 // uncomment in case of 1071 errors (requires SUPER privileges)
176 // db_query("SET @@global.innodb_large_prefix=1", "Cannot set large prefix");
178 // site default encoding is presumed as encoding for all databases!
179 $lang = array_search_value($dflt_lang, $installed_languages, 'code');
180 $new_encoding = get_mysql_encoding_name(strtoupper($lang['encoding']));
182 $this->log_error(sprintf('Switching database to utf8 encoding from %s', $old_encoding), 'Info');
183 $collation = get_mysql_collation($this->collation);
184 $tsql = "SHOW TABLES LIKE '".($pref=='' ? '' : substr($pref, 0, -1).'\\_')."%'";
185 $tresult = db_query($tsql, "Cannot select all tables with prefix '$pref'");
186 while($tbl = db_fetch($tresult)) {
189 db_query("ALTER TABLE `$table` CONVERT TO CHARACTER SET $old_encoding"); // convert encoding on utf-8 tables
191 // set proper default table encoding for current user language (used on binary->text conversion)
192 db_query("ALTER TABLE `$table` CHARSET $new_encoding");
193 $csql = "SHOW COLUMNS FROM $table";
194 $cresult = db_query($csql, "Cannot select column names for table '$table'");
197 $to_binary = $to_default = $to_utf = array();
198 while($col = db_fetch($cresult)) {
200 $bintype = strtr($col['Type'], array('varchar' => 'varbinary', 'char'=>'varbinary', 'text'=>'blob', 'tinytext'=>'tinyblob'));
202 if ($bintype != $col['Type'])
203 { // this is char/text column, so change encoding to proper encoding
205 $this->log_error(sprintf('%s switched to uft8.', $table.'.'.$col['Field']), 'Debug');
207 $null = $col['Null'] === 'YES' ? ' NULL ' : ' NOT NULL ';
208 $default = $col['Null'] !== 'YES' && isset($col['Default']) ? ' DEFAULT '.db_escape($col['Default']) : '';
210 // to avoid column width multiplication x3 we old->binary->ui->utf column type change instead of column CONVERT
212 $to_binary[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$bintype;
213 $to_default[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$col['Type'].$null.$default;
214 $to_utf[] = "MODIFY COLUMN `".$col['Field']."` ".$col['Type']." COLLATE ".$collation.$null.$default;
218 if(count($to_binary))
220 $sql = "ALTER TABLE `$table` ".implode(',',$to_binary);
222 $sql = "ALTER TABLE `$table` ".implode(',',$to_default);
224 $sql = "ALTER TABLE `$table` ".implode(',',$to_utf);
227 db_query("ALTER TABLE `$table` COLLATE $collation");
229 db_query("ALTER DATABASE COLLATE $collation");
230 $this->log_error(_('Convertion to utf8 done.'), 'Info');
235 function update_grn_rates()
237 $sql = "SELECT grn.id, grn.delivery_date, supp.curr_code
238 FROM ".TB_PREF."grn_batch grn, ".TB_PREF."suppliers supp
239 WHERE supp.supplier_id=grn.supplier_id AND supp.curr_code!='".get_company_pref('curr_default')."'";
240 $result = db_query($sql);
245 $sql = "UPDATE ".TB_PREF."grn_batch SET rate=%s WHERE id=%d";
246 while ($grn = db_fetch($result))
247 db_query(sprintf($sql, get_exchange_rate_from_home_currency($grn['curr_code'], sql2date($grn['delivery_date'])), $grn['id']));
252 function do_cleanup()
256 //remove obsolete and temporary columns.
257 // this have to be done here as db_import rearranges alter query order
259 'tax_groups' => array('tax_shipping'),
260 'tax_group_items' => array('rate'),
261 'budget_trans' => array('type', 'type_no', 'person_id', 'person_type_id', 'memo_'),
262 'cust_branch' => array('contact_name', 'disable_trans'),
263 'stock_moves' => array('discount_percent', 'visible', 'person_id'),
266 foreach($dropcol as $table => $columns)
267 foreach($columns as $col) {
268 if (db_query("ALTER TABLE `".TB_PREF."{$table}` DROP `$col`") == false) {
269 return $this->log_error(sprintf(_("Cannot drop column in %s table: %s"), $table, db_error_msg($db)));
276 $install = new fa2_4;