Created new fiscal year, 2016-01-01 to 2016-12-31.
[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.1'; // 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.4RC1');
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_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                 if ($result)
79                 {
80                         $db_connections[$company]['collation'] = $this->collation;
81                         if (write_config_db())
82                                 return $this->log_error(_("Cannot update config_db.php file."));
83                 }
84
85                 $sec_updates = array(
86                         'SA_SETUPCOMPANY' => array(
87                                 'SA_ASSET', 'SA_ASSETCATEGORY', 'SA_ASSETCLASS',
88                                 'SA_ASSETSTRANSVIEW','SA_ASSETTRANSFER', 'SA_ASSETDISPOSAL',
89                                 'SA_DEPRECIATION', 'SA_ASSETSANALYTIC'),
90                 );
91                 $result = $this->update_security_roles($sec_updates);
92
93                 return $result;
94         }
95
96         //
97         // optional procedure done after upgrade fail, before backup is restored
98         //
99         function post_fail($company)
100         {
101                 $pref = $this->companies[$company]['tbpref'];
102                 db_query("DROP TABLE IF EXISTS " . $pref . 'wo_costing');
103                 db_query("DROP TABLE IF EXISTS " . $pref . 'stock_fa_class');
104                 db_query("DELETE FROM ".$pref."sys_prefs
105                         WHERE `name` in (
106                                 'gl_closing_date', 'deferred_income_act', 'no_zero_lines_amount', 'accounts_alpha',
107                                 'tax_algorithm', 'grn_clearing_act', 'default_receival_required',
108                                 'default_quote_valid_days',     'no_zero_lines_amount', 'show_po_item_codes', 'accounts_alpha',
109                                 'loc_notification', 'print_invoice_no', 'allow_negative_prices', 'print_item_images_on_quote',
110                                 'bcc_email', 'alternative_tax_include_on_docs', 'suppress_tax_rates')");
111         }
112
113         function update_workorders()
114         {
115                 global $db;
116
117                 $sql = "SELECT DISTINCT type, type_no, tran_date, person_id FROM ".TB_PREF."gl_trans WHERE `type`=".ST_WORKORDER
118                         ." AND person_type_id=1";
119                 $res = db_query($sql);
120                 if (!$res)
121                         return $this->log_error(sprintf(_("Cannot update work orders costs:\n%s"), db_error_msg($db)));
122
123                 while ($row = db_fetch($res))
124                 {
125                         $journal_id = get_next_trans_no(ST_JOURNAL);
126
127                         $sql1 = "UPDATE ".TB_PREF."gl_trans SET `type`=".ST_JOURNAL.", type_no={$journal_id},
128                                 person_type_id=NULL, person_id=0
129                                 WHERE `type`=".ST_WORKORDER." AND type_no={$row['type_no']} AND tran_date='{$row['tran_date']}'
130                                 AND person_id='{$row['person_id']}'";
131                         if (!db_query($sql1)) return false;
132
133                         $sql2 = "INSERT INTO ".TB_PREF."wo_costing (workorder_id, cost_type, trans_no) 
134                                 VALUES ({$row['type_no']}, {$row['person_id']}, {$journal_id})";
135                         if (!db_query($sql2)) return false;
136                 }
137                 return true;
138         }
139
140 /*
141         In previous versions FA ignored encoding settings on database/tables, so it depended on server settings,
142         but data stored is encoded in user language encoding. Now we switch to utf8 internal database encoding, while
143         user encoding can be selected independently.
144
145         To perform safe FA database switch to utf-8 encoding we have to first ensure that all text/char columns 
146         have properly set encoding (the same as its content), so the algorithm performed on every table is as follows:
147         . set default table encoding for the table to currently used on client side;
148         . for all text/char column:
149          - suppress autorecoding by change of the type to related binary/blob type
150          - change column to utf8 encodding and selected collation.
151         . change default table encoding to utf8 and selected collation
152 */
153         function switch_database_to_utf($pref, $dbg = false) {
154
155                 global $installed_languages, $dflt_lang;
156
157                 $old_encoding = 'latin1'; // default client encoding
158
159                 // uncomment in case of 1071 errors (requires SUPER privileges)
160                 // db_query("SET @@global.innodb_large_prefix=1", "Cannot set large prefix");
161
162                  // site default encoding is presumed as encoding for all databases!
163                 $lang = array_search_value($dflt_lang, $installed_languages, 'code');
164                 $new_encoding = get_mysql_encoding_name(strtoupper($lang['encoding']));
165
166                 $this->log_error(sprintf('Switching database to utf8 encoding from %s', $old_encoding), 'Info');
167                 $collation = get_mysql_collation($this->collation);
168                 $tsql = "SHOW TABLES LIKE '".($pref=='' ? '' : substr($pref, 0, -1).'\\_')."%'";
169                 $tresult = db_query($tsql, "Cannot select all tables with prefix '$pref'");
170                 while($tbl = db_fetch($tresult)) {
171                         $table = $tbl[0];
172
173                         db_query("ALTER TABLE `$table` CONVERT TO CHARACTER SET $old_encoding"); // convert encoding on utf-8 tables
174
175                         // set proper default table encoding for current user language (used on binary->text conversion)
176                         db_query("ALTER TABLE `$table` CHARSET $new_encoding");
177                         $csql = "SHOW COLUMNS FROM $table";
178                         $cresult = db_query($csql, "Cannot select column names for table '$table'");
179                         $convert = false;
180
181                         $to_binary = $to_default = $to_utf = array();
182                         while($col = db_fetch($cresult)) {
183
184                                 $bintype = strtr($col['Type'], array('varchar' => 'varbinary', 'char'=>'varbinary', 'text'=>'blob', 'tinytext'=>'tinyblob'));
185
186                                 if ($bintype != $col['Type'])
187                                 { // this is char/text column, so change encoding to proper encoding
188                                         if ($dbg)
189                                                 $this->log_error(sprintf('%s switched to uft8.', $table.'.'.$col['Field']), 'Debug');
190
191                                         $null = $col['Null'] === 'YES' ? ' NULL ' : ' NOT NULL ';
192                                         $default = $col['Null'] !== 'YES' && isset($col['Default']) ? ' DEFAULT '.db_escape($col['Default']) : '';
193
194                                         // to avoid column width multiplication x3 we old->binary->ui->utf column type change instead of column CONVERT
195
196                                         $to_binary[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$bintype;
197                                         $to_default[] = "CHANGE `".$col['Field']."` `".$col['Field']."` ".$col['Type'].$null.$default;
198                                         $to_utf[] = "MODIFY COLUMN `".$col['Field']."` ".$col['Type']." COLLATE ".$collation.$null.$default;
199                                         $convert = true;
200                                 }
201                         }
202                         if(count($to_binary))
203                         {
204                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_binary);
205                                 db_query($sql);
206                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_default);
207                                 db_query($sql);
208                                 $sql = "ALTER TABLE `$table` ".implode(',',$to_utf);
209                                 db_query($sql);
210                         }
211                         db_query("ALTER TABLE `$table` COLLATE $collation");
212                 }
213                 db_query("ALTER DATABASE COLLATE $collation");
214                 $this->log_error(_('Convertion to utf8 done.'), 'Info');
215
216                 return true;
217         }
218
219         function update_grn_rates()
220         {
221                 $sql = "SELECT grn.id, grn.delivery_date, supp.curr_code 
222                         FROM ".TB_PREF."grn_batch grn, ".TB_PREF."suppliers supp
223                         WHERE supp.supplier_id=grn.supplier_id AND supp.curr_code!='".get_company_pref('curr_default')."'";
224                 $result = db_query($sql);
225
226                 if (!$result)
227                         return false;
228
229                 $sql = "UPDATE ".TB_PREF."grn_batch SET rate=%s WHERE id=%d";
230                 while ($grn = db_fetch($result))
231                         db_query(sprintf($sql, get_exchange_rate_from_home_currency($grn['curr_code'], sql2date($grn['delivery_date'])), $grn['id']));
232
233                 return true;
234         }
235
236         function do_cleanup()
237         {
238                 global $db;
239
240                 //remove obsolete and temporary columns.
241                 // this have to be done here as db_import rearranges alter query order
242                 $dropcol = array(
243                                 'tax_groups' => array('tax_shipping'),
244                                 'tax_group_items' => array('rate'),
245                                 'budget_trans' => array('type', 'type_no', 'person_id', 'person_type_id', 'memo_'),
246                                 'cust_branch' => array('contact_name', 'disable_trans'),
247                                 'stock_moves' => array('discount_percent', 'visible', 'person_id'),
248                 );
249
250                 foreach($dropcol as $table => $columns)
251                         foreach($columns as $col) {
252                                 if (db_query("ALTER TABLE `".TB_PREF."{$table}` DROP `$col`") == false) {
253                                         return $this->log_error(sprintf(_("Cannot drop column in %s table: %s"), $table, db_error_msg($db)));
254                                 }
255                         }
256                 return true;
257   }
258 }
259
260 $install = new fa2_4;