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 var $version = '2.3'; // version installed
15 var $sql = 'alter2.3.sql';
17 var $beta = false; // upgrade from 2.2 or 2.3beta;
20 $this->description = _('Upgrade from version 2.2 to 2.3');
24 // Install procedure. All additional changes
25 // not included in sql file should go here.
27 function install($pref, $force)
29 global $db_version, $dflt_lang;
35 // all specials below are already done on 2.3beta
37 $sql = "SELECT debtor_no, payment_terms FROM {$pref}debtors_master";
39 $result = db_query($sql);
41 display_error("Cannot read customers"
42 .':<br>'. db_error_msg($db));
45 // update all sales orders and transactions with customer std payment terms
46 while($cust = db_fetch($result)) {
47 $sql = "UPDATE {$pref}debtor_trans SET "
48 ."payment_terms = '" .$cust['payment_terms']
49 ."' WHERE debtor_no='".$cust['debtor_no']."'";
50 if (db_query($sql)==false) {
51 display_error("Cannot update cust trans payment"
52 .':<br>'. db_error_msg($db));
55 $sql = "UPDATE {$pref}sales_orders SET "
56 ."payment_terms = '" .$cust['payment_terms']
57 ."' WHERE debtor_no='".$cust['debtor_no']."'";
58 if (db_query($sql)==false) {
59 display_error("Cannot update sales order payment"
60 .':<br>'. db_error_msg($db));
64 if (!$this->update_totals($pref)) {
65 display_error("Cannot update order totals");
68 if (!$this->update_line_relations($pref)) {
69 display_error("Cannot update sales document links");
72 //remove obsolete and temporary columns.
73 // this have to be done here as db_import rearranges alter query order
75 'crm_persons' => array('tmp_id','tmp_class'),
76 'debtors_master' => array('email'),
77 'cust_branch' => array('phone', 'phone2', 'fax', 'email'),
78 'suppliers' => array('phone', 'phone2', 'fax', 'email'),
79 'debtor_trans' => array('trans_link')
82 foreach($dropcol as $table => $columns)
83 foreach($columns as $col) {
84 if (db_query("ALTER TABLE `{$pref}{$table}` DROP `$col`")==false) {
85 display_error("Cannot drop {$table}.{$col} column:<br>".db_error_msg($db));
89 // remove old preferences table after upgrade script has been executed
90 $sql = "DROP TABLE IF EXISTS `{$pref}company`";
94 $this->update_lang_cfg();
95 return update_company_prefs(array('version_id'=>$db_version), $pref);
98 // Checking before install
100 function pre_check($pref, $force)
103 if ($this->beta && !$force)
104 $this->sql = 'alter2.3rc.sql';
109 // Test if patch was applied before.
111 function installed($pref) {
112 $this->beta = !check_table($pref, 'suppliers', 'tax_included');
113 $this->preconf = $this->fix_extensions();
115 $n = 1; // number of patches to be installed
120 if (!check_table($pref, 'comments', 'type', array('Key'=>'MUL'))) $patchcnt++;
121 if (!check_table($pref, 'sys_prefs')) $patchcnt++;
122 if (!check_table($pref, 'sales_orders', 'payment_terms')) $patchcnt++;
124 if (!check_table($pref, 'purch_orders', 'tax_included')) $patchcnt++;
125 return $n == $patchcnt ? true : ($patchcnt ? ($patchcnt.'/'. $n) : 0);
127 //=========================================================================================
128 // 2.3 specific update functions
134 function update_totals($pref)
136 global $path_to_root;
138 include_once("$path_to_root/sales/includes/cart_class.inc");
139 include_once("$path_to_root/purchasing/includes/po_class.inc");
140 $cart = new cart(ST_SALESORDER);
141 $sql = "SELECT order_no FROM {$pref}sales_orders";
142 $orders = db_query($sql);
146 while ($order_no = db_fetch($orders)) {
147 read_sales_order($order_no[0], $cart, ST_SALESORDER);
148 $result = db_query("UPDATE {$pref}sales_orders SET total=".$cart->get_trans_total());
149 unset($cart->line_items);
152 $cart = new purch_order();
153 $sql = "SELECT order_no FROM {$pref}purch_orders";
154 $orders = db_query($sql);
157 while ($order_no = db_fetch($orders)) {
158 read_po($order_no[0], $cart);
159 $result = db_query("UPDATE {$pref}purch_orders SET total=".$cart->get_trans_total());
160 unset($cart->line_items);
165 //------------------------------------------------------------------------------
166 // Retreive parent document number(s) for given transaction
168 function get_parent_trans_2_2($trans_type, $trans_no) {
170 $sql = 'SELECT trans_link FROM
171 '.TB_PREF.'debtor_trans WHERE trans_no='.db_escape($trans_no)
172 .' AND type='.db_escape($trans_type).' AND trans_link!=0';
174 $result = db_query($sql, 'Parent document numbers cannot be retrieved');
176 if (db_num_rows($result)) {
177 $link = db_fetch($result);
178 return array($link['trans_link']);
180 if ($trans_type!=ST_SALESINVOICE) return 0; // this is credit note with no parent invoice
181 // invoice: find batch invoice parent trans.
182 $sql = 'SELECT trans_no FROM
183 '.TB_PREF.'debtor_trans WHERE
184 (trans_link='.db_escape($trans_no).' AND type='. get_parent_type($trans_type) .')';
186 $result = db_query($sql, 'Delivery links cannot be retrieved');
189 if(db_num_rows($result)>0) {
190 while($link = db_fetch($result)) {
191 $delivery[] = $link['trans_no'];
194 return count($delivery) ? $delivery : 0;
198 Reorganizing document relations. Due to the design issue in pre 2.3 db structure
199 there can be sales documents with lines not properly linked to parents. This rare
200 cases will be described in error log.
202 function update_line_relations($pref)
204 global $path_to_root, $systypes_array;
206 require_once("$path_to_root/includes/sysnames.inc");
208 $sql = "SELECT d.type, trans_no, order_ FROM {$pref}debtor_trans d
209 LEFT JOIN {$pref}voided v ON d.type=v.type AND d.trans_no=v.id
210 WHERE ISNULL(v.type) AND
211 (d.type=".ST_CUSTDELIVERY
212 ." OR d.type=".ST_SALESINVOICE
213 ." OR d.type=".ST_CUSTCREDIT.")";
214 $result = db_query($sql);
218 while ($trans = db_fetch($result)) {
219 $type = $trans['type'];
220 $trans_no = $trans['trans_no'];
224 $lines = get_customer_trans_details($type, $trans_no);
225 $n = db_num_rows($lines);
227 if ($type==ST_CUSTDELIVERY)
228 $src_lines = get_sales_order_details($trans['order_'], ST_SALESORDER);
230 $src_lines = get_customer_trans_details(get_parent_type($type),
231 $this->get_parent_trans_2_2($type, $trans_no));
233 $src_n = db_num_rows($src_lines);
235 if (($type == ST_CUSTCREDIT) && ($src_n == 0))
236 continue; // free credit note has no src lines
238 $max = $type == ST_CUSTDELIVERY ? $n : max($src_n, $n);
240 for($i = 0, $j=0; $i < $max; $i++) {
241 if (!($doc_line = @db_fetch($lines)))
244 if(!($src_line = @db_fetch($src_lines)))
247 if ($type == ST_CUSTDELIVERY)
248 $src_line['stock_id'] = $src_line['stk_code']; // SO details has another field name
250 if ($src_line['stock_id'] == $doc_line['stock_id']
251 && ($src_line['quantity'] >= $doc_line['quantity'])) {
253 $sql = "UPDATE {$pref}debtor_trans_details SET src_id = {$src_line['id']}
254 WHERE id = {$doc_line['id']}";
261 error_log("Line level relations error for ".$systypes_array[$type]." #$trans_no.");
267 function fix_extensions()
269 global $path_to_root, $next_extension_id, $installed_languages;
272 foreach($installed_languages as $i => $lang) {
273 if (!isset($lang['path'])) {
274 $code = $lang['code'];
275 $installed_languages[$i]['path'] = 'lang/'.$code;
276 $installed_languages[$i]['package'] = $code;
283 $installed_extensions= get_company_extensions();
285 if (!isset($next_extension_id))
286 $next_extension_id = 1;
289 foreach($installed_extensions as $i => $ext)
291 if (isset($ext['title'])) // old type entry
293 if ($ext['type'] == 'module') {
294 $new['type'] = 'extension';
295 $new['tabs'][] = array(
296 'url' => $ext['filename'],
297 'access' => isset($ext['access']) ? $ext['access'] : 'SA_OPEN',
298 'tab_id' => $ext['tab'],
299 'title' => $ext['title']
301 $new['path'] = $ext['path'];
305 $new['type'] = 'extension';
306 $new['tabs'] = array();
307 $new['path'] = 'modules/'.$ext['path'];
308 $new['entries'][] = array(
309 'url' => $ext['filename'],
310 'access' => isset($ext['access']) ? $ext['access'] : 'SA_OPEN',
311 'tab_id' => $ext['tab'],
312 'title' => $ext['title']
315 if (isset($ext['acc_file']))
316 $new['acc_file'] = $ext['acc_file'];
317 $new['name'] = $ext['name']; // albo access_string(title)
318 $new['package'] = $new['package'] = '';
321 $new_exts[$i] = $new;
324 // Add non-standard themes
325 $path = $path_to_root.'/themes/';
327 $themedir = opendir($path);
328 while (false !== ($fname = readdir($themedir)))
330 if ($fname!='.' && $fname!='..' && $fname!='CVS' && is_dir($path.$fname)
331 && !in_array($fname, array('aqua', 'cool', 'default')))
333 foreach($installed_extensions as $ext)
334 if ($ext['path'] == 'themes/'.$fname) // skip if theme is already listed
336 $new_exts[$next_extension_id++] = array(
337 'name' => 'Theme '. ucwords($fname),
341 'path' => 'themes/'.$fname
347 if (count($new_exts)) {
348 return update_extensions($new_exts);
353 function update_lang_cfg()
355 global $dflt_lang, $installed_languages;
357 foreach($installed_languages as $n => $lang) {
358 if ($lang['code'] == 'en_GB') {
359 $installed_languages[$n] = array('code'=>'C','name'=>'English',
360 'encoding'=>'iso-8859-1', 'path' => '', 'package' => '');
361 if ($dflt_lang == 'en_GB')
369 $install = new fa2_3;