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