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