Additional fixes to app options reorganization.
[fa-stable.git] / sql / alter2.4.php
1 <?php
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 ***********************************************************************/
12 class fa2_4 {
13         var $version = '2.4.0'; // version installed
14         var $description;
15         var $sql = 'alter2.4.sql';
16         var $preconf = true;
17         
18         function fa2_4() {
19                 $this->description = _('Upgrade from version 2.3 to 2.4');
20         }
21         
22         //
23         //      Install procedure. All additional changes 
24         //      not included in sql file should go here.
25         //
26         function install($company, $force=false) 
27         {
28                 global $db_version, $db_connections;
29
30                 $pref = $db_connections[$company]['tbpref'];
31
32                 if (get_company_pref('grn_clearing_act') === null) { // available form 2.3.1, can be not defined on pre-2.4 installations
33                         set_company_pref('grn_clearing_act', 'glsetup.purchase', 'varchar', 15, 0);
34                 }
35                 if (get_company_pref('default_quote_valid_days') === null) { // new in 2.3.23 installations
36                         set_company_pref('default_quote_valid_days', 'glsetup.sales', 'smallint', 6, 30);
37                 }
38                 if (get_company_pref('bcc_email') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
39                         set_company_pref('bcc_email', 'setup.company', 'varchar', 100, '');
40                 }
41                 if (get_company_pref('alternative_tax_include_on_docs') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
42                         set_company_pref('alternative_tax_include_on_docs', 'setup.company', 'tinyint', 1, '0');
43                 }
44                 if (get_company_pref('suppress_tax_rates') === null) { // available from 2.3.14, can be not defined on pre-2.4 installations
45                         set_company_pref('suppress_tax_rates', 'setup.company', 'tinyint', 1, '0');
46                 }
47
48                 $result = $this->update_workorders()  && $this->update_grn_rates() && $this->switch_database_to_utf($pref);
49
50                 if ($result)
51                         $result = $this->do_cleanup();
52
53                 return  update_company_prefs(array('version_id'=>$db_version));
54         }
55         //
56         //      Checking before install
57         //
58         function pre_check($pref, $force)
59         {
60                 return true;
61         }
62
63         //
64         // optional procedure done after upgrade fail, before backup is restored
65         //
66         function post_fail($pref)
67         {
68                 db_query("DROP TABLE IF EXISTS " . $pref . 'wo_costing');
69         }
70         //
71         //      Test if patch was applied before.
72         //
73         function installed($pref)
74         {
75                 $n = 2; // number of patches to be installed
76                 $patchcnt = 0;
77
78                 if (!check_table($pref, 'suppliers', 'tax_algorithm')) $patchcnt++;
79                 if (!check_table($pref, 'wo_costing')) $patchcnt++;
80                 return $n == $patchcnt ? true : ($patchcnt ? ($patchcnt.'/'. $n) : 0);
81         }
82
83         function update_workorders()
84         {
85                 global $db;
86
87                 $sql = "SELECT DISTINCT type, type_no, tran_date, person_id FROM ".TB_PREF."gl_trans WHERE `type`=".ST_WORKORDER
88                 ." AND person_type_id=1";
89                 $res = db_query($sql);
90                 if (!$res)
91                 {
92                         display_error("Cannot update work orders costs"
93                                 .':<br>'. db_error_msg($db));
94                         return false;
95                 }
96                 while ($row = db_fetch($res))
97                 {
98                         $journal_id = get_next_trans_no(ST_JOURNAL);
99
100                         $sql1 = "UPDATE ".TB_PREF."gl_trans SET `type`=".ST_JOURNAL.", type_no={$journal_id},
101                                 person_type_id=NULL, person_id=0
102                                 WHERE `type`=".ST_WORKORDER." AND type_no={$row['type_no']} AND tran_date='{$row['tran_date']}'
103                                 AND person_id='{$row['person_id']}'";
104                         if (!db_query($sql1)) return false;
105                         
106                         $sql2 = "INSERT INTO ".TB_PREF."wo_costing (workorder_id, cost_type, trans_no) 
107                                 VALUES ({$row['type_no']}, {$row['person_id']}, {$journal_id})";
108                         if (!db_query($sql2)) return false;
109                 }
110                 return true;
111         }
112
113 /*
114         In previous versions FA ignored encoding settings on database/tables, so it depended on server settings,
115         but data stored is encoded in user language encoding. Now we switch to utf8 internal database encoding, while
116         user encoding can be selected independently.
117
118         To perform safe FA database switch to utf-8 encoding we have to first ensure that all text/char columns 
119         have properly set encoding (the same as its content), so the algorithm performed on every table is as follows:
120         . set default table encoding for the table to currently used on client side;
121         . for all text/char column:
122          - suppress autorecoding by change of the type to related binary/blob type
123          - change column to utf8 encodding and selected collation.
124         . change default table encoding to utf8
125 */
126         function switch_database_to_utf($pref, $test = false) {
127
128                 global $installed_languages, $dflt_lang;
129
130                 $old_encoding = 'latin1'; // default client encoding
131
132                  // site default encoding is presumed as encoding for all databases!
133                 $lang = array_search_value($dflt_lang, $installed_languages, 'code');
134                 $new_encoding = get_mysql_encoding_name(strtoupper($lang['encoding']));
135         //      get_usec();
136                 if ($test)
137                         error_log('Switching database to utf8 encoding from '.$old_encoding);
138                 $collation = get_mysql_collation();
139                 $tsql = "SHOW TABLES LIKE '".($pref=='' ? '' : substr($pref, 0, -1).'\\_')."%'";
140                 $tresult = db_query($tsql, "Cannot select all tables with prefix '$pref'");
141                 while($tbl = db_fetch($tresult)) {
142                         $table = $tbl[0];
143                 // if ($table != '1_chart_master') continue; _vd($table); get_usec(); // fast debug on single table
144
145                         db_query("ALTER TABLE `$table` CONVERT TO CHARACTER SET $old_encoding"); // convert encoding on utf-8 tables
146
147                         // set proper default table encoding for current user language (used on binary->text conversion)
148                         db_query("ALTER TABLE `$table` CHARSET $new_encoding");
149                         $csql = "SHOW COLUMNS FROM $table";
150                         $cresult = db_query($csql, "Cannot select column names for table '$table'");
151                         $convert = false;
152
153                         $to_binary = $to_default = $to_utf = array();
154                         while($col = db_fetch($cresult)) {
155
156                                 $bintype = strtr($col['Type'], array('varchar' => 'varbinary', 'char'=>'varbinary', 'text'=>'blob', 'tinytext'=>'tinyblob'));
157
158                                 if ($bintype != $col['Type'])
159                                 { // this is char/text column, so change encoding to proper encoding
160                                         if ($test)
161                                                 error_log($table.'.'.$col['Field']);
162
163                                         $null = $col['Null'] === 'YES' ? ' NULL ' : ' NOT NULL ';
164                                         $default = $col['Null'] !== 'YES' && isset($col['Default']) ? ' DEFAULT '.db_escape($col['Default']) : '';
165
166                                         // to avoid column width multiplication x3 we old->binary->ui->utf column type change instead of column CONVERT
167
168                                         $to_binary[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$bintype;
169                                         $to_default[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$col['Type'].$null.$default;
170                                         $to_utf[] = "MODIFY COLUMN `".$col['Field']."` ".$col['Type']." COLLATE ".$collation.$null.$default;
171                                         $convert = true;
172                                 }
173                         }
174                         if(count($to_binary))
175                         {
176                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_binary);
177                                 db_query($sql);
178                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_default);
179                                 db_query($sql);
180                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_utf);
181                                 db_query($sql);
182                         }
183                         db_query("ALTER TABLE `$table` COLLATE $collation");
184                 }
185                 db_query("ALTER DATABASE COLLATE $collation");
186                 if ($test)
187                         error_log('Convertion to utf8 done.');
188
189                 return true;
190         }
191
192         function update_grn_rates()
193         {
194                 $sql = "SELECT grn.id, grn.delivery_date, supp.curr_code 
195                         FROM ".TB_PREF."grn_batch grn, ".TB_PREF."suppliers supp
196                         WHERE supp.supplier_id=grn.supplier_id AND supp.curr_code!='".get_company_pref('curr_default')."'";
197                 $result = db_query($sql);
198
199                 if (!$result)
200                         return false;
201
202                 $sql = "UPDATE ".TB_PREF."grn_batch SET rate=%s WHERE id=%d";
203                 while ($grn = db_fetch($result))
204                         db_query(sprintf($sql, get_exchange_rate_from_home_currency($grn['curr_code'], sql2date($grn['delivery_date'])), $grn['id']));
205
206                 return true;
207         }
208
209         function do_cleanup()
210         {
211                 $dropcol = array(
212                                 'tax_group_items' => array('rate'),
213                                 'budget_trans' => array('type', 'type_no', 'person_id', 'person_type_id', 'memo_'),
214                 );
215
216                 foreach($dropcol as $table => $columns)
217                         foreach($columns as $col) {
218                                 if (db_query("ALTER TABLE `".TB_PREF."{$table}` DROP `$col`") == false) {
219                                         display_error("Cannot drop {$table}.{$col} column:<br>".db_error_msg($db));
220                                         return false;
221                                 }
222                         }
223         }
224 }
225
226 $install = new fa2_4;