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');
21 $this->preconf = $this->fix_extensions();
25 // Install procedure. All additional changes
26 // not included in sql file should go here.
28 function install($pref, $force)
36 // all specials below are already done on 2.3beta
38 $sql = "SELECT debtor_no, payment_terms FROM {$pref}debtors_master";
40 $result = db_query($sql);
42 display_error("Cannot read customers"
43 .':<br>'. db_error_msg($db));
46 // update all sales orders and transactions with customer std payment terms
47 while($cust = db_fetch($result)) {
48 $sql = "UPDATE {$pref}debtor_trans SET "
49 ."payment_terms = '" .$cust['payment_terms']
50 ."' WHERE debtor_no='".$cust['debtor_no']."'";
51 if (db_query($sql)==false) {
52 display_error("Cannot update cust trans payment"
53 .':<br>'. db_error_msg($db));
56 $sql = "UPDATE {$pref}sales_orders SET "
57 ."payment_terms = '" .$cust['payment_terms']
58 ."' WHERE debtor_no='".$cust['debtor_no']."'";
59 if (db_query($sql)==false) {
60 display_error("Cannot update sales order payment"
61 .':<br>'. db_error_msg($db));
65 if (!$this->update_totals($pref)) {
66 display_error("Cannot update order totals");
69 if (!$this->update_line_relations($pref)) {
70 display_error("Cannot update sales document links");
73 //remove obsolete and temporary columns.
74 // this have to be done here as db_import rearranges alter query order
76 'crm_persons' => array('tmp_id','tmp_class'),
77 'debtors_master' => array('email'),
78 'cust_branch' => array('phone', 'phone2', 'fax', 'email'),
79 'suppliers' => array('phone', 'phone2', 'fax', 'email'),
80 'debtor_trans' => array('trans_link')
83 foreach($dropcol as $table => $columns)
84 foreach($columns as $col) {
85 if (db_query("ALTER TABLE `{$pref}{$table}` DROP `$col`")==false) {
86 display_error("Cannot drop {$table}.{$col} column:<br>".db_error_msg($db));
90 // remove old preferences table after upgrade script has been executed
91 $sql = "DROP TABLE IF EXISTS `{$pref}company`";
95 return update_company_prefs(array('version_id'=>$core_version), $pref);
98 // Checking before install
100 function pre_check($pref, $force)
102 if ($this->beta && !$force)
103 $this->sql = 'alter2.3rc.sql';
108 // Test if patch was applied before.
110 function installed($pref) {
111 $this->beta = !check_table($pref, 'suppliers', 'tax_included');
113 $n = 1; // number of patches to be installed
118 if (!check_table($pref, 'comments', 'type', array('Key'=>'MUL'))) $patchcnt++;
119 if (!check_table($pref, 'sys_prefs')) $patchcnt++;
120 if (!check_table($pref, 'sales_orders', 'payment_terms')) $patchcnt++;
122 if (!check_table($pref, 'purch_orders', 'tax_included')) $patchcnt++;
123 return $n == $patchcnt ? true : ($patchcnt ? ($patchcnt.'/'. $n) : 0);
125 //=========================================================================================
126 // 2.3 specific update functions
132 function update_totals($pref)
134 global $path_to_root;
136 include_once("$path_to_root/sales/includes/cart_class.inc");
137 include_once("$path_to_root/purchasing/includes/po_class.inc");
138 $cart = new cart(ST_SALESORDER);
139 $sql = "SELECT order_no FROM {$pref}sales_orders";
140 $orders = db_query($sql);
144 while ($order_no = db_fetch($orders)) {
145 read_sales_order($order_no[0], $cart, ST_SALESORDER);
146 $result = db_query("UPDATE {$pref}sales_orders SET total=".$cart->get_trans_total());
147 unset($cart->line_items);
150 $cart = new purch_order();
151 $sql = "SELECT order_no FROM {$pref}purch_orders";
152 $orders = db_query($sql);
155 while ($order_no = db_fetch($orders)) {
156 read_po($order_no[0], $cart);
157 $result = db_query("UPDATE {$pref}purch_orders SET total=".$cart->get_trans_total());
158 unset($cart->line_items);
163 //------------------------------------------------------------------------------
164 // Retreive parent document number(s) for given transaction
166 function get_parent_trans_2_2($trans_type, $trans_no) {
168 $sql = 'SELECT trans_link FROM
169 '.TB_PREF.'debtor_trans WHERE trans_no='.db_escape($trans_no)
170 .' AND type='.db_escape($trans_type).' AND trans_link!=0';
172 $result = db_query($sql, 'Parent document numbers cannot be retrieved');
174 if (db_num_rows($result)) {
175 $link = db_fetch($result);
176 return array($link['trans_link']);
178 if ($trans_type!=ST_SALESINVOICE) return 0; // this is credit note with no parent invoice
179 // invoice: find batch invoice parent trans.
180 $sql = 'SELECT trans_no FROM
181 '.TB_PREF.'debtor_trans WHERE
182 (trans_link='.db_escape($trans_no).' AND type='. get_parent_type($trans_type) .')';
184 $result = db_query($sql, 'Delivery links cannot be retrieved');
187 if(db_num_rows($result)>0) {
188 while($link = db_fetch($result)) {
189 $delivery[] = $link['trans_no'];
192 return count($delivery) ? $delivery : 0;
196 Reorganizing document relations. Due to the design issue in pre 2.3 db structure
197 there can be sales documents with lines not properly linked to parents. This rare
198 cases will be described in error log.
200 function update_line_relations($pref)
202 global $path_to_root, $systypes_array;
204 require_once("$path_to_root/includes/sysnames.inc");
206 $sql = "SELECT d.type, trans_no, order_ FROM {$pref}debtor_trans d
207 LEFT JOIN {$pref}voided v ON d.type=v.type AND d.trans_no=v.id
208 WHERE ISNULL(v.type) AND
209 (d.type=".ST_CUSTDELIVERY
210 ." OR d.type=".ST_SALESINVOICE
211 ." OR d.type=".ST_CUSTCREDIT.")";
212 $result = db_query($sql);
216 while ($trans = db_fetch($result)) {
217 $type = $trans['type'];
218 $trans_no = $trans['trans_no'];
222 $lines = get_customer_trans_details($type, $trans_no);
223 $n = db_num_rows($lines);
225 if ($type==ST_CUSTDELIVERY)
226 $src_lines = get_sales_order_details($trans['order_'], ST_SALESORDER);
228 $src_lines = get_customer_trans_details(get_parent_type($type),
229 $this->get_parent_trans_2_2($type, $trans_no));
231 $src_n = db_num_rows($src_lines);
233 if (($type == ST_CUSTCREDIT) && ($src_n == 0))
234 continue; // free credit note has no src lines
236 $max = $type == ST_CUSTDELIVERY ? $n : max($src_n, $n);
238 for($i = 0, $j=0; $i < $max; $i++) {
239 if (!($doc_line = @db_fetch($lines)))
242 if(!($src_line = @db_fetch($src_lines)))
245 if ($type == ST_CUSTDELIVERY)
246 $src_line['stock_id'] = $src_line['stk_code']; // SO details has another field name
248 if ($src_line['stock_id'] == $doc_line['stock_id']
249 && ($src_line['quantity'] >= $doc_line['quantity'])) {
251 $sql = "UPDATE {$pref}debtor_trans_details SET src_id = {$src_line['id']}
252 WHERE id = {$doc_line['id']}";
259 error_log("Line level relations error for ".$systypes_array[$type]." #$trans_no.");
265 function fix_extensions()
267 global $path_to_root, $next_extension_id, $installed_languages;
270 foreach($installed_languages as $i => $lang) {
271 if (!isset($lang['path'])) {
272 $code = $lang['code'];
273 $installed_languages[$i]['path'] = 'lang/'.$code;
274 $installed_languages[$i]['package'] = $code;
281 $installed_extensions= get_company_extensions();
283 if (!isset($next_extension_id))
284 $next_extension_id = 1;
287 foreach($installed_extensions as $i => $ext)
289 if (isset($ext['title'])) // old type entry
291 if ($ext['type'] == 'module') {
292 $new['type'] = 'extension';
293 $new['tabs'][] = array(
294 'url' => $ext['filename'],
295 'access' => isset($ext['access']) ? $ext['access'] : 'SA_OPEN',
296 'tab_id' => $ext['tab'],
297 'title' => $ext['title']
299 $new['path'] = $ext['path'];
303 $new['type'] = 'extension';
304 $new['tabs'] = array();
305 $new['path'] = 'modules/'.$ext['path'];
306 $new['entries'][] = array(
307 'url' => $ext['filename'],
308 'access' => isset($ext['access']) ? $ext['access'] : 'SA_OPEN',
309 'tab_id' => $ext['tab'],
310 'title' => $ext['title']
313 if (isset($ext['acc_file']))
314 $new['acc_file'] = $ext['acc_file'];
315 $new['name'] = $ext['name']; // albo access_string(title)
316 $new['package'] = $new['package'] = '';
319 $new_exts[$i] = $new;
322 // Add non-standard themes
323 $path = $path_to_root.'/themes/';
325 $themedir = opendir($path);
326 while (false !== ($fname = readdir($themedir)))
328 if ($fname!='.' && $fname!='..' && $fname!='CVS' && is_dir($path.$fname)
329 && !in_array($fname, array('aqua', 'cool', 'default')))
331 foreach($installed_extensions as $ext)
332 if ($ext['path'] == 'themes/'.$fname) // skip if theme is already listed
334 $new_exts[$next_extension_id++] = array(
335 'name' => 'Theme '. ucwords($fname),
339 'path' => 'themes/'.$fname
345 if (count($new_exts)) {
346 return update_extensions($new_exts);
352 $install = new fa2_3;