Rewritten upgrade procedures, added fa_patch class, utf8 collation can be set before...
authorJanusz Dobrowolski <janusz@frontaccounting.eu>
Fri, 23 Jan 2015 18:28:46 +0000 (19:28 +0100)
committerJanusz Dobrowolski <janusz@frontaccounting.eu>
Fri, 23 Jan 2015 21:15:59 +0000 (22:15 +0100)
20 files changed:
admin/backups.php
admin/db/company_db.inc
admin/includes/fa_patch.class.inc [new file with mode: 0644]
admin/includes/index.php [new file with mode: 0644]
admin/inst_module.php
admin/inst_upgrade.php
admin/view/view_upgrade_log.php [new file with mode: 0644]
config.default.php
includes/db/connect_db.inc
includes/db/connect_db_mysqli.inc
includes/prefs/sysprefs.inc
includes/ui/ui_input.inc
includes/ui/view_package.php
sql/alter2.1.php
sql/alter2.2.php
sql/alter2.3.php
sql/alter2.4.php
themes/aqua/images/log.png [new file with mode: 0644]
themes/cool/images/log.png [new file with mode: 0644]
themes/default/images/log.png [new file with mode: 0644]

index 2831c131747a115e4a6917a87f5a6481c3f98cf0..1168b4f2fc9ce803268684f45a1c581502411c96 100644 (file)
@@ -16,13 +16,11 @@ include_once($path_to_root . "/includes/session.inc");
 include_once($path_to_root . "/includes/ui.inc");
 include_once($path_to_root . "/admin/db/maintenance_db.inc");
 
-define("BACKUP_PATH", $SysPrefs->comp_path.'/'.user_company()."/backup/");
-
 if (get_post('view')) {
        if (!get_post('backups')) {
                display_error(_('Select backup file first.'));
        } else {
-               $filename = BACKUP_PATH . clean_file_name(get_post('backups'));
+               $filename = $SysPrefs->backup_dir().clean_file_name(get_post('backups'));
                if (in_ajax()) 
                        $Ajax->popup( $filename );
                else {
@@ -36,7 +34,7 @@ if (get_post('view')) {
 };
 if (get_post('download')) {
        if (get_post('backups')) {
-               download_file(BACKUP_PATH . clean_file_name(get_post('backups')));
+               download_file($SysPrefs->backup_dir().clean_file_name(get_post('backups')));
                exit;
        } else
                display_error(_("Select backup file first."));
@@ -48,10 +46,12 @@ check_paths();
 
 function check_paths()
 {
-       if (!file_exists(BACKUP_PATH)) {
+  global $SysPrefs;
+
+       if (!file_exists($SysPrefs->backup_dir())) {
                display_error (_("Backup paths have not been set correctly.") 
                        ._("Please contact System Administrator.")."<br>" 
-                       . _("cannot find backup directory") . " - " . BACKUP_PATH . "<br>");
+                       . _("cannot find backup directory") . " - " . $SysPrefs->backup_dir() . "<br>");
                end_page();
                exit;
        }
@@ -59,7 +59,9 @@ function check_paths()
 
 function generate_backup($conn, $ext='no', $comm='')
 {
-       $filename = db_backup($conn, $ext, $comm, BACKUP_PATH);
+       global $SysPrefs;
+
+       $filename = db_backup($conn, $ext, $comm, $SysPrefs->backup_dir());
        if ($filename)
                display_notification(_("Backup successfully generated."). ' '
                        . _("Filename") . ": " . $filename);
@@ -72,11 +74,11 @@ function generate_backup($conn, $ext='no', $comm='')
 
 function get_backup_file_combo()
 {
-       global $path_to_root, $Ajax;
+       global $path_to_root, $Ajax, $SysPrefs;
        
        $ar_files = array();
     default_focus('backups');
-    $dh = opendir(BACKUP_PATH);
+    $dh = opendir($SysPrefs->backup_dir());
        while (($file = readdir($dh)) !== false)
                $ar_files[] = $file;
        closedir($dh);
@@ -127,7 +129,7 @@ function download_file($filename)
 
 $conn = $db_connections[user_company()];
 $backup_name = clean_file_name(get_post('backups'));
-$backup_path = BACKUP_PATH . $backup_name;
+$backup_path = $SysPrefs->backup_dir() . $backup_name;
 
 if (get_post('creat')) {
        generate_backup($conn, get_post('comp'), get_post('comments'));
@@ -165,7 +167,7 @@ if (get_post('upload'))
                if (!preg_match("/\.sql(\.zip|\.gz)?$/", $fname))
                        display_error(_("You can only upload *.sql backup files"));
                elseif (is_uploaded_file($tmpname)) {
-                       rename($tmpname, BACKUP_PATH . $fname);
+                       rename($tmpname, $SysPrefs->backup_dir() . $fname);
                        display_notification(_("File uploaded to backup directory"));
                        $Ajax->activate('backups');
                } else
index 3f1718ca20e661540bac445b130b322eda644efe..a983436090a0335a134b0890739b3c81c12bbfb3 100644 (file)
@@ -82,8 +82,9 @@ function set_company_pref($pref, $category, $type, $length, $value)
 
 function refresh_sys_prefs()
 {
-       flush_dir(user_js_cache()); // clear cache
+//     flush_dir(user_js_cache()); // clear cache
        unset($_SESSION['SysPrefs']);
+       $_SESSION['SysPrefs'] = new sys_prefs();
        get_company_prefs();
 }
 
diff --git a/admin/includes/fa_patch.class.inc b/admin/includes/fa_patch.class.inc
new file mode 100644 (file)
index 0000000..631df82
--- /dev/null
@@ -0,0 +1,256 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+
+//
+//     Utility class contains basic database upgrade routines.
+//
+class fa_patch {
+       var $previous;                          // previous database version 
+       var $version;                           // version after upgrade
+       var $description;                       // short patch description
+
+       var $sql;                                       // basic sql file
+
+       var $cur_company;
+       var $backup;                            // pre-upgrade backup filename
+
+       var $errors = array();
+       var     $ma_upgrade_time = 300;
+
+       function fa_patch()
+       {
+               global $path_to_root;
+
+               include $path_to_root."/config_db.php";
+
+               $this->companies = $db_connections;
+
+               return $this->companies;
+       }
+
+       /*
+               Collect/log messages generated during upgrade process.
+       */
+       function log_error($msg, $type='Error')
+       {
+               if ($type == 'Error')
+                       $this->errors[] = $msg;
+               error_log(sprintf('[%s] %s', $type, $msg));
+               return false;
+       }
+
+       /*
+               Pre-install maintenance: login to company, open upgrade log, make a backup
+       */
+       function pre_install($company)
+       {
+               global $SysPrefs;
+
+               $this->cur_company = $company;
+               $this->errors = array();
+               $this->backup = null;
+
+               $this->save_log = ini_set('error_log', dirname(__FILE__).'/../../tmp/upgrade.'.$this->cur_company.'.log');
+               $this->log_error(sprintf(_("Upgrade started for company %s."), $this->cur_company), 'Info');
+
+               if (!set_global_connection($this->cur_company))
+                       return $this->log_error(_("Cannot connect to company database."));
+
+               $cur_ver = get_company_pref('version_id', true);
+               if ($cur_ver != $this->previous)
+                       return $this->log_error(sprintf(_("Cannot upgrade company %s: database version is incompatible ('%s' instead of '%s')."),
+                               $this->cur_company, $cur_ver, $this->previous));
+
+               if (!$this->prepare())  // fetch params, perform additional checks (if any)
+                 return false;
+
+               if (!$this->sql)
+                       return true;    // skip security backup if database content is not changed
+
+               $this->backup = db_backup($this->companies[$this->cur_company], 'no', 'Security backup before upgrade',
+                       $SysPrefs->backup_dir($this->cur_company));
+
+               if (!$this->backup)
+                 return $this->log_error(_("Security backup failed."));
+
+               $this->log_error(sprintf(_("Security backup in file %s done."), $this->backup), 'Info');
+               return true;
+       }
+
+       /*
+               Basic install procedure using sql file.
+       */
+       function sql_install($company, $force=false) 
+       {
+               global $path_to_root;
+
+               if ($this->sql != '')   // perform basic upgrade operations defined in sql file
+               {
+                       $result = true;
+
+                       if ($result === true)
+                               $result = db_import($path_to_root. '/sql/'.$this->sql, $this->companies[$company],
+                                       $force, true, false, true);
+
+                       if ($result !== true)
+                       {
+                               if (is_array($result))
+                               {
+                                       foreach($result as $err)
+                                               $this->log_error($err[1] . ':'. $err[0]);
+                               } else
+                               {
+                                       $this->log_error($result);
+                                       unset($this->backup); // prevent restore (database was not touched due to other errors)
+                               }
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       /*
+               Post install procedures: update database version, or restore databse from backup file in case of errors
+       */
+       function post_install($result=true)
+       {
+               global $db_version;
+
+               if ($result !== true)
+               {
+                       if ($this->backup)
+                       {
+                               if (!set_global_connection($this->cur_company)) // reset connection to clear encoding
+                                       return $this->log_error(_("Cannot connect to company database for database restore."));
+
+                               set_time_limit($this->max_upgrade_time);
+                               $result = db_import($this->backup, $this->companies[$this->cur_company], true, false);
+                               if ($result)
+                                       $this->log_error(_("Upgrade failed. Original database content restored successfully."), 'Info');
+                               else
+                                       $thi->log_error(sprintf(_("Database restore operation failed. Original database content is in %s file."), $this->backup));
+                               $this->post_fail($this->cur_company);
+                       }
+               } else {
+                       update_company_prefs(array('version_id' => $this->version));
+               }
+
+               $this->log_error(sprintf(_("Upgrade for company %s finished."), $this->cur_company), 'Info');
+
+               set_global_connection();
+               ini_set('error_log', $this->save_log);
+
+               if (db_fixed())
+                       db_set_encoding();
+
+               return $result;
+       }
+
+       /*
+               Main routine for single company upgrade.
+       */
+       function upgrade_company($comp, $force=false)
+       {
+               $result = $this->pre_install($comp) && $this->sql_install($comp, $force) && $this->install($comp, $force);
+
+               $this->post_install($result);
+
+               return count($this->errors) == 0;
+       }
+
+       /*
+               Additional version specific php/sql upgrade procedures.
+               This procedure is performed after basic sql upgrade script is run.
+       */
+       function install($company, $force=false) 
+       {
+               return true;
+       }
+       /*
+               Optional cleanup procedure.
+               This procedure is run in case of upgrade failure, before the backup is restored.
+       */
+       function post_fail($company)
+       {
+       }
+
+    /*
+               Present upgrade parameters to administrator
+               This function presents upgrade choices, after selection company to be upgraded.
+    */
+       function show_params($comp)
+    {
+       }
+
+    /*
+           Fetch & check upgrade parameters, check additional upgrade pre-conditions.
+               This function is run after successfull switching to target database connection.
+    */
+       function prepare()
+    {
+               return true;
+       }
+
+}
+
+/*
+       Return databases status info.
+*/
+function get_site_status($connections)
+{
+               $info = array();
+
+               foreach($connections as $i => $conn)
+               {
+                       $info[$i]['status'] = set_global_connection($i) !== false;
+
+                       $info[$i]['name'] = $conn['name'];
+                       $info[$i]['table_set'] = $conn['host'].'/'.$conn['dbname'].':'.$conn['tbpref'].'*';
+                       if ($info[$i]['status'])
+                       {
+                               $info[$i]['version'] = get_company_pref('version_id');
+                       }
+               }
+               set_global_connection();
+               refresh_sys_prefs();
+
+               return $info;
+}
+
+/*
+       Creates table of installer objects sorted by applicable db scheme version.
+*/
+function get_installers()
+{
+       global $path_to_root;
+
+       $patchdir = $path_to_root."/sql/";
+       $upgrades = array();    
+       $datadir = @opendir($patchdir);
+
+       if ($datadir)
+       {
+               while(false !== ($fname = readdir($datadir)))
+               { // check all php files but index.php
+                       if (!is_dir($patchdir . $fname) && ($fname != 'index.php')
+                               && stristr($fname, '.php') != false && $fname[0] != '.')
+                       {
+                               unset($install);
+                               include_once($patchdir . $fname);
+                               if (isset($install)) // add installer if found
+                                       $upgrades[$install->previous] =  $install;
+                       }
+               }
+               ksort($upgrades); // sort by file name
+       }
+       return $upgrades;
+}
diff --git a/admin/includes/index.php b/admin/includes/index.php
new file mode 100644 (file)
index 0000000..e88dc9e
--- /dev/null
@@ -0,0 +1,2 @@
+<?php
+header("Location: ../index.php");
index eda65097e50426d5cfb4337ffc908d2772792a1d..01169034e2563ff95b02e00efe67a59fb85e8db9 100644 (file)
@@ -17,7 +17,7 @@ include_once($path_to_root."/includes/packages.inc");
 if ($SysPrefs->use_popup_windows) {
        $js = get_js_open_window(900, 500);
 }
-page(_($help_context = "Install/Activate extensions"));
+page(_($help_context = "Install/Activate extensions"), false, false, "", $js);
 
 include_once($path_to_root . "/includes/date_functions.inc");
 include_once($path_to_root . "/admin/db/company_db.inc");
index 16eee5a7a06ceaaf5c49bcc9dbecf25945650407..948594f8e6adf7b735668bae1d0d31b8847e6a69 100644 (file)
@@ -13,168 +13,107 @@ $page_security = 'SA_SOFTWAREUPGRADE';
 $path_to_root="..";
 include_once($path_to_root . "/includes/session.inc");
 
-page(_($help_context = "Software Upgrade"));
+if ($SysPrefs->use_popup_windows) {
+       $js = get_js_open_window(900, 500);
+}
+page(_($help_context = "Software Upgrade"), false, false, "", $js);
 
 include_once($path_to_root . "/includes/date_functions.inc");
 include_once($path_to_root . "/admin/db/company_db.inc");
 include_once($path_to_root . "/admin/db/maintenance_db.inc");
 include_once($path_to_root . "/includes/ui.inc");
+include_once($path_to_root . "/admin/includes/fa_patch.class.inc");
+
+$site_status = get_site_status($db_connections);
+$installers = get_installers();
 
-//
-//     Creates table of installer objects sorted by version.
-//
-function get_installers()
+if (get_post('Upgrade')) 
 {
-       global $path_to_root;
+       $comp = get_post('select_comp');
 
-       $patchdir = $path_to_root."/sql/";
-       $upgrades = array();    
-       $datadir = @opendir($patchdir);
+    if ($comp === '')
+               display_error(_('Select company to be upgraded.'));
+       else {
+               $patch = @$installers[$site_status[$comp]['version']];
+               if ($patch)
+               {
+                       if (!$patch->upgrade_company($comp, check_value('force')))
+                               display_error(implode('<hr>', $patch->errors));
+                       else
+                               display_notification(_("Company upgraded successfully."));
 
-       if ($datadir)
-       {
-               while(false !== ($fname = readdir($datadir)))
-               { // check all php files but index.php
-                       if (!is_dir($patchdir . $fname) && ($fname != 'index.php')
-                               && stristr($fname, '.php') != false && $fname[0] != '.')
-                       {
-                               unset($install);
-                               include_once($patchdir . $fname);
-                               if (isset($install)) // add installer if found
-                                       $upgrades[$install->version] =  $install;
-                       }
+                       $site_status = get_site_status($db_connections); // update info
+                   $Ajax->activate('_page_body');
                }
-               ksort($upgrades); // sort by file name
-               $upgrades = array_values($upgrades);
        }
-       return $upgrades;
 }
-//
-//     Apply one differential data set.
-//
-function upgrade_step($inst, $company, $conn, $force) 
+$i = find_submit('Clear');
+if ($i != -1)
 {
-       global $path_to_root;
-
-       $pref = $conn['tbpref'];
-       $ret = true;
+  unlink($path_to_root.'/tmp/upgrade.'.$i.'.log');
+  $Ajax->activate('_page_body');
+}
+if (get_post('_select_comp_update'))
+{
+  $Ajax->activate('_page_body');
+}
 
-               $state = $inst->installed($pref);
-               if (!$state || $force) 
-               {
-                       if (!$inst->pre_check($pref, $force)) return false;
-                       $sql = $inst->sql;
+start_form();
 
-                       error_log(sprintf(_("Database upgrade for company '%s' (%s:%s*) started..."),
-                               $conn['name'], $conn['dbname'], $conn['tbpref']));
+$th = array(_("Company"), _("Table set"), _("Current version"), _("Last log"), _('Upgrade'));
+start_table(TABLESTYLE);
+table_header($th);
 
-                       if ($sql != '')
-                               $ret &= db_import($path_to_root.'/sql/'.$sql, $conn, $force, true);
+$uptodate = true;
+foreach($site_status as $i => $comp)
+{
+       $status = $comp['version']==$db_version;
 
-                       $ret &= $inst->install($company, $force);
+       alt_table_row_color($k);
 
-                       if (!$ret && is_callable(array($inst, 'post_fail')))
-                               $inst->post_fail($pref);
+       label_cell($comp['name']);
+       label_cell($comp['table_set']);
 
-                       error_log(_("Database upgrade finished."));
-               } else
-                       if ($state!==true) {
-                               display_error(_("Upgrade cannot be done because database has been already partially upgraded. Please downgrade database to clean previous version or try forced upgrade."));
-                               $ret = false;
-                       }
-       return $ret;
-}
+       label_cell($comp['version'], 'align=center' .($status ? '':' class=redfg')/*, 'class='.( $status ? 'ok' : 'error')*/);
 
-$installers = get_installers();
+       $log = $path_to_root.'/tmp/upgrade.'.$i.'.log';
+       if (file_exists($log))
+       {
+               label_cell(viewer_link(_('View log'), "admin/view/view_upgrade_log.php?id=$i", null, $i, 'log.png')
+                 .button('Clear'.$i, _('Clear'), _('Clear log'), ICON_DELETE), 'align=center');
+               submit_js_confirm('Clear'.$i, _("Do you really want to clear this upgrade log?"));
+       } else
+               label_cell('-', 'align=center');
 
-if (get_post('Upgrade')) 
-{
 
-       $ret = true;
-       foreach ($db_connections as $comp => $conn) 
+       if (!$status)
        {
-       // connect to database
-               if (!(set_global_connection($comp))) 
-               {
-                       display_error(_("Cannot connect to database for company")
-                               ." '".$conn['name']."'");
-                       continue;
-               }
-       // create security backup       
-               db_backup($conn, 'no', 'Security backup before upgrade');
-       // apply all upgrade data
-               foreach ($installers as $i => $inst) 
-               {
-
-                       $force = get_post('force_'.$i);
-                       if ($force || get_post('install_'.$i)) 
-                               $ret = upgrade_step($installers[$i], $comp, $conn, $force);
-
-                       if (!$ret)
-                       {
-                               display_error(
-                               sprintf(_("Database upgrade to version %s failed for company '%s'."),
-                                       $inst->version, $conn['name'])
-                                       .'<br>'
-                                       ._('You should restore company database from latest backup file'));
-                       }
-               }
-//             db_close($conn); ?
-               if (!$ret) break;
-       }
-       set_global_connection();
-       if($ret)
-       {       // re-read the prefs
-               global $path_to_root;
-               include_once($path_to_root . "/admin/db/users_db.inc");
-               $user = get_user_by_login($_SESSION["wa_current_user"]->username);
-               $_SESSION["wa_current_user"]->prefs = new user_prefs($user);
-               display_notification(_('All companies data has been successfully updated'));
-       }       
-       refresh_sys_prefs(); // re-read system setup
-       $Ajax->activate('_page_body');
+               label_cell(radio(null, 'select_comp', $i, null, true), 'align=center');
+               $uptodate = false;
+       } else
+               label_cell(_('Up to date'));
+       end_row();
 }
 
-start_form();
-start_table(TABLESTYLE);
-$th = array(_("Version"), _("Description"), _("Sql file"), _("Install"),
-       _("Force upgrade"));
-table_header($th);
+end_table();
+br();
 
-$k = 0; //row colour counter
-$partial = 0;
-foreach($installers as $i => $inst)
+div_start('upgrade_args');
+if (get_post('select_comp') !== '')
 {
-       alt_table_row_color($k);
-       start_row();
-       label_cell($inst->version);
-       label_cell($inst->description);
-       label_cell($inst->sql ? $inst->sql : '<i>'._('None').'</i>', 'align=center');
-// this is checked only for first (site admin) company, 
-// but in fact we should always upgrade all data sets after
-// source upgrade.
-       $check = $inst->installed(TB_PREF);
-       if ($check === true)
-               label_cell(_("Installed"));
-       else 
-               if (!$check)
-                       check_cells(null,'install_'.$i, 0);
-               else {
-                       label_cell("<span class=redfg>"
-                               . sprintf(_("Partially installed (%s)"), $check) . "</span>");
-                       $partial++;
-               }
-
-       check_cells(null,'force_'.$i, 0);
-       end_row();
+       $patch = @$installers[$site_status[get_post('select_comp')]['version']];
+       if ($patch)
+               $patch->show_params(get_post('select_comp'));
 }
-end_table(1);
-if ($partial!=0)       {
-       display_note(_("Database upgrades marked as partially installed cannot be installed automatically.
-You have to clean database manually to enable them, or try to perform forced upgrade."));
-       br();
+div_end();
+
+if ($uptodate)
+       display_note(_('All company database schemes are up to date.'));
+else {
+       if (get_post('select_comp') === '')
+               display_note(_("Select company for incremental upgrade."), 0, 1, "class='stockmankofg'");
+       submit_center('Upgrade', _('Upgrade'), true, _('Save database and perform upgrade'), 'process');
 }
-submit_center('Upgrade', _('Upgrade system'), true, _('Save database and perform upgrade'), 'process');
 end_form();
 
 end_page();
diff --git a/admin/view/view_upgrade_log.php b/admin/view/view_upgrade_log.php
new file mode 100644 (file)
index 0000000..e1cbd0f
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**********************************************************************
+    Copyright (C) FrontAccounting, LLC.
+       Released under the terms of the GNU General Public License, GPL, 
+       as published by the Free Software Foundation, either version 3 
+       of the License, or (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+    See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
+***********************************************************************/
+$page_security = 'SA_SOFTWAREUPGRADE';
+$path_to_root = "../..";
+include_once($path_to_root . "/includes/session.inc");
+include_once($path_to_root . "/includes/packages.inc");
+
+page(_($help_context = "Log View"), true);
+
+include_once($path_to_root . "/includes/ui.inc");
+
+if (!isset($_GET['id'])) 
+{
+       /*Script was not passed the correct parameters */
+       display_note(_("The script must be called with a valid company number."));
+       end_page();
+}
+
+display_heading(sprintf(_("Upgrade log for company '%s'"), $_GET['id']));
+br();
+  start_table();
+       start_row();
+
+       $log = strtr(file_get_contents($path_to_root.'/tmp/upgrade.'.$_GET['id'].'.log'), 
+                 array('Fatal error' => 'Fatal  error')); // prevent misinterpretation in output_handler
+    label_cells(null, nl2br(html_specials_encode($log)));
+       end_row();
+  end_table(1);
+end_page(true);
index 02075ef5691ffb7f21740036d1e85a9b268e53c1..57ac00c3f0846652c0cf3a2c89540f7161985cb5 100644 (file)
@@ -91,7 +91,7 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
        $help_base_url = null;
 
        /* per user data/cache directory */
-       $comp_path = $path_to_root.'/company';
+       $comp_path = dirname(__FILE__).'/company';
 
        /* Date systems. 0 = traditional, 1 = Jalali used by Iran, nabour countries, Afghanistan and some other Central Asian nations,
        2 = Islamic used by other arabic nations. 3 = traditional, but where non-workday is Friday and start of week is Saturday */
@@ -200,3 +200,8 @@ if (!isset($path_to_root) || isset($_GET['path_to_root']) || isset($_POST['path_
 */
        $clear_trial_balance_opening = false;
 
+/*
+       Optional backup path. Use %s in place of company number.
+       If not defined $comp_path/%s/backup/ is used.
+*/
+//     $backup_path = dirname(__FILE__).'/company/%s/backup/';
index 98a18f59824085e7ca0f20366132549271904720..a689946b8637a96e1218fec77133c3677bb510e2 100644 (file)
@@ -90,7 +90,7 @@ function get_mysql_collation($lang=null)
                'it' => 'roman',
        );
 
-       return 'utf8_'.(isset($db_collation[$lang]) ? $db_collation[$lang] : 'general').'_ci';
+       return 'utf8_'.(isset($db_collation[$lang]) ? $db_collation[$lang] : 'unicode').'_ci';
 }
 
 /*
index 7359a85c6f731bd0629764361ea3eca42ff87fca..45439f047cec8d71a0626bd13dbc17ab931e4658 100644 (file)
@@ -37,6 +37,7 @@ function set_global_connection($company=-1)
        ///// We are, however, investigating the existing code to be compatible in the future.
                db_query("SET sql_mode = '".SQL_MODE."'");
        /////
+       refresh_sys_prefs();
        return $db;
 }
 
index ee3fa70bafeadaf36193265ae5f4e5f43776d472..0ff68cbdc3bafe972d9a7ac012ba17c1683be576 100644 (file)
@@ -145,5 +145,16 @@ class sys_prefs
        {
                return $this->prefs['suppress_tax_rates'];
        }
+
+       function backup_dir($comp=null)
+       {
+               if (!isset($comp))
+                       $comp = user_company();
+
+               if (isset($this->backup_path))
+                       return sprintf($this->backup_path, $comp);
+               else
+                       return $this->comp_path.'/'.$comp."/backup/";
+       }
 }
 
index b3cb79b17d024c7fbe5c487910f605cc3cb3c5a6..862032859bcbb9dd39784587da74a31335b2c7b7 100644 (file)
@@ -387,7 +387,7 @@ function check_row($label, $name, $value=null, $submit_on_change=false, $title=f
 function radio($label, $name, $value, $selected=null, $submit_on_change=false)
 {
        if (!isset($selected))
-               $selected = get_post($name) == $value;
+               $selected = get_post($name) === (string)$value;
 
        if ($submit_on_change === true)
                $submit_on_change = 
index dee8a2f9945df7fe4fb03248e100c0ee426f141e..6d957720e98dfec2a3bfd7056302330c63566fa1 100644 (file)
@@ -51,7 +51,7 @@ foreach ($pkg as $field => $value) {
        if ($value == '')
                continue;
        start_row();
-       label_cells($field, nl2br(htmlentities(is_array($value) ? implode("\n", $value) :$value)),
+       label_cells($field, nl2br(html_specials_encode(is_array($value) ? implode("\n", $value) :$value)),
                 "class='tableheader2'");
        end_row();
 }
index cd8eb86532391776da49bd76472074083eb626e7..a70f15a32b9a566a889bc3b6e69dc80a6b719532 100644 (file)
@@ -9,7 +9,8 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
-class fa2_1 {
+class fa2_1 extends fa_patch {
+       var $previous = '';             // applicable database version
        var $version = '2.1';   // version installed
        var $description;
        var $sql = 'alter2.1.sql';
@@ -21,7 +22,7 @@ class fa2_1 {
        //      Install procedure. All additional changes 
        //      not included in sql file should go here.
        //
-       function install($company, $force) 
+       function install($company, $force=false
        {
                global $db;
 
@@ -128,13 +129,16 @@ class fa2_1 {
                
                return true;
        }
+
        //
        //      Checking before install
        //
-       function pre_check($pref)
+       function prepare()
        {
        // We cannot perform successfull upgrade on system where the
-       // trans tax details tables was deleted during previous try.  
+       // trans tax details tables was deleted during previous try.
+               $pref = $this->companies[$company]['tbpref'];
+
                if (check_table($pref, 'debtor_trans_tax_details') 
                        || check_table($pref, 'supp_invoice_tax_items')) {
                        display_error(_("Seems that system upgrade to version 2.1 has 
@@ -143,23 +147,10 @@ class fa2_1 {
                        database restore from last backup file first."));
 
                        return false;
-               } 
+               }
 
                return true; // true when ok, fail otherwise
        }
-       //
-       //      Test if patch was applied before.
-       //
-       function installed($pref) {
-               $n = 4; // number of features to be installed
-               if (!check_table($pref, 'item_codes')) $n--;
-//             if (!check_table($pref, 'company', 'foreign_codes')) $n--;
-               if (!check_table($pref, 'suppliers', 'credit_limit')) $n--;
-               if (!check_table($pref, 'bank_trans', 'reconciled', 
-                       array('Type'=>'date'))) $n--;
-               if (!check_table($pref, 'trans_tax_details')) $n--;
-               return $n == 0 ? true : 5 - $n;
-       }
 };
 
 $install = new fa2_1;
index 981079fe18f6b6d96d786484b4abb3a18f2a37bd..837f44cefc69a52918f6da2cb6a2ecc1e287d877 100644 (file)
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
 
-class fa2_2 {
-       var $version = '2.2';   // version installed
+class fa2_2 extends fa_patch  {
+       var $previous = '2.1';          // applicable database version
+       var $version = '2.2rc'; // version installed
        var $description;
        var $sql = 'alter2.2.sql';
        var $preconf = true;
-       var $beta = false; // upgrade from 2.1 or 2.2beta; set in pre_check
+       var $beta = false; // upgrade from 2.1 or 2.2beta; set in prepare()
        
        function fa2_2() {
                global $security_groups;
@@ -28,10 +29,10 @@ class fa2_2 {
        //      Install procedure. All additional changes 
        //      not included in sql file should go here.
        //
-       function install($company, $force) 
+       function install($company, $force=false
        {
                global $db, $systypes_array, $db_connections;
-               
+
                if (!$this->preconf)
                        return false;
 
@@ -101,48 +102,17 @@ class fa2_2 {
        //
        //      Checking before install
        //
-       function pre_check($pref, $force)
-       {       
+       function prepare()
+       {
                global $security_groups;
-               
-               if ($this->beta && !$force)
+
+               if ($this->beta)
                        $this->sql = 'alter2.2rc.sql';
                // return ok when security groups still defined (upgrade from 2.1)
                // or usersonline not defined (upgrade from 2.2 beta)
-               return isset($security_groups) || (check_table($pref, 'usersonline')!=0);
-       }
-       //
-       //      Test if patch was applied before.
-       //
-       function installed($pref) {
-               $n = 1; // number of patches to be installed
-               $patchcnt = 0;
-               if (!$this->beta) {
-                       $n = 16;
-                       if (check_table($pref, 'company')) // skip in 2.3
-                               $n -= 3;
-                       else {
-                               if (check_table($pref, 'company', 'custom1_name')) $patchcnt++;
-                               if (!check_table($pref, 'company', 'profit_loss_year_act'))     $patchcnt++;
-                               if (!check_table($pref, 'company', 'login_tout')) $patchcnt++;
-                       }
-                       if (!check_table($pref, 'stock_category', 'dflt_no_sale')) $patchcnt++;
-                       if (!check_table($pref, 'users', 'sticky_doc_date')) $patchcnt++;
-                       if (!check_table($pref, 'users', 'startup_tab')) $patchcnt++;
-                       if (!check_table($pref, 'cust_branch', 'inactive')) $patchcnt++;
-                       if (!check_table($pref, 'chart_class', 'ctype')) $patchcnt++;
-                       if (!check_table($pref, 'audit_trail')) $patchcnt++;
-                       if (!check_table($pref, 'currencies', 'auto_update')) $patchcnt++;
-                       if (!check_table($pref, 'stock_master','no_sale')) $patchcnt++;
-                       if (!check_table($pref, 'suppliers', 'supp_ref')) $patchcnt++;
-                       if (!check_table($pref, 'users', 'role_id')) $patchcnt++;
-                       if (!check_table($pref, 'sales_orders', 'reference')) $patchcnt++;
-                       if (!check_table($pref, 'tags')) $patchcnt++;
-               } 
-               if (!check_table($pref, 'useronline')) $patchcnt++;
+               $pref = $this->companies[$company]['tbpref'];
 
-               $n -= $patchcnt;
-               return $n == 0 ? true : $patchcnt;
+               return isset($security_groups) || (check_table($pref, 'usersonline')!=0);
        }
 };
 
index 0fa5e2606487e1e36425096a8308757c43d57bd2..f186ff62315a077b9967c3ed97b9be6e2e49c80e 100644 (file)
@@ -9,8 +9,9 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
-class fa2_3 {
-       var $version = '2.3';   // version installed
+class fa2_3 extends fa_patch {
+       var $previous = '2.2rc';                // applicable database version
+       var $version = '2.3rc'; // version installed
        var $description;
        var $sql = 'alter2.3.sql';
        var $preconf = true;
@@ -24,7 +25,7 @@ class fa2_3 {
        //      Install procedure. All additional changes 
        //      not included in sql file should go here.
        //
-       function install($company, $force) 
+       function install($company, $force=false
        {
                global $db_version, $dflt_lang;
 
@@ -98,36 +99,19 @@ class fa2_3 {
        //
        //      Checking before install
        //
-       function pre_check($pref, $force)
+       function prepare()
        {
 
-               if ($this->beta && !$force)
+               if ($this->beta)
                        $this->sql = 'alter2.3rc.sql';
 
                return true;
        }
-       //
-       //      Test if patch was applied before.
-       //
-       function installed($pref) {
-               $this->beta = !check_table($pref, 'suppliers', 'tax_included');
-
-               $n = 1; // number of patches to be installed
-               $patchcnt = 0;
 
-               if (!$this->beta) {
-                       $n += 3;
-                       if (!check_table($pref, 'comments', 'type', array('Key'=>'MUL'))) $patchcnt++;
-                       if (!check_table($pref, 'sys_prefs')) $patchcnt++;
-                       if (!check_table($pref, 'sales_orders', 'payment_terms')) $patchcnt++;
-               }
-               if (!check_table($pref, 'purch_orders', 'tax_included')) $patchcnt++;
-               return $n == $patchcnt ? true : ($patchcnt ? ($patchcnt.'/'. $n) : 0);
-       }
        //=========================================================================================
        //      2.3 specific update functions
        //
-       
+
        /*
                Update order totals
        */
@@ -264,11 +248,11 @@ class fa2_3 {
                }
        return true;
        }
-       
+
        function fix_extensions()
        {
                global $path_to_root, $next_extension_id, $installed_languages;
-               
+
                $lang_chd = false;
                foreach($installed_languages as $i => $lang) {
                        if (!isset($lang['path'])) {
@@ -281,15 +265,14 @@ class fa2_3 {
                if ($lang_chd)
                        write_lang();
 
-               
                $installed_extensions= get_company_extensions();
                if (!isset($next_extension_id))
                        $next_extension_id = 1;
                $new_exts = array();
-               
+
 /*     Old extension modules are uninstalled - they need manual porting after 
        heavy changes in extension system in FA2.3
-       
+
                foreach($installed_extensions as $i => $ext)
                {
                        if (isset($ext['title'])) // old type entry
index c51f19962c7a347ee82d4abbafa951006674b8be..7fc60b38716106f89dd2fbcb08948fde3e0db8a8 100644 (file)
@@ -9,21 +9,81 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
 ***********************************************************************/
-class fa2_4 {
+function collations_list_row($label, $name, $selected_id=null)
+{
+
+$mysql_collations = array(
+  'xx' => 'Unicode (multilanguage)',
+  'is' => 'Icelandic',
+  'lv' => 'Latvian',
+  'ro' => 'Romanian',
+  'sl' => 'Slovenian',
+  'pl' => 'Polish',
+  'et' => 'Estonian',
+  'es' => 'Spanish', // or 'spanish2',
+  'sw' => 'Swedish',
+  'tr' => 'Turkish',
+  'cs' => 'Czech',
+  'da' => 'Danish',
+  'lt' => 'Lithuanian',
+  'sk' => 'Slovak',
+  'sp' => 'Spanish (alternative)',
+  'fa' => 'Persian',
+  'hu' => 'Hungarian',
+  'fr' => 'French',
+  'it' => 'Italian',
+);
+
+       echo "<tr>";
+       if ($label != null)
+               echo "<td class='label'>$label</td>\n";
+       echo "<td>";
+
+       echo array_selector($name, $selected_id, $mysql_collations, 
+               array('select_submit'=> false) );
+       echo "</td></tr>\n";
+}
+
+class fa2_4 extends fa_patch {
+       var $previous = '2.3rc';                // applicable database version
        var $version = '2.4.0'; // version installed
        var $description;
        var $sql = 'alter2.4.sql';
        var $preconf = true;
        
        function fa2_4() {
+               parent::fa_patch();
                $this->description = _('Upgrade from version 2.3 to 2.4');
        }
        
+    /*
+           Shows parameters to be selected before upgrade (if any)
+       */
+    function show_params($comp)
+       {
+         display_note(_('Set optimal parameters and start upgrade:'));
+         start_table(TABLESTYLE);
+         start_row();
+               collations_list_row(_('Text collation optimization:'), 'collation', substr($_SESSION['language']->code, 0, 2));
+         end_row();
+         end_table();
+         br();
+    }
+
+       /*
+           Fetches selected upgrade parameters.
+    */
+       function prepare()
+    {
+               $this->collation = get_mysql_collation(get_post('collation'));
+               return true;
+       }
+
        //
        //      Install procedure. All additional changes 
        //      not included in sql file should go here.
        //
-       function install($company, $force=false) 
+       function install($company, $force=false)
        {
                global $db_version, $db_connections;
 
@@ -50,49 +110,17 @@ class fa2_4 {
                if ($result)
                        $result = $this->do_cleanup();
 
-               //remove obsolete and temporary columns.
-               // this have to be done here as db_import rearranges alter query order
-               $dropcol = array(
-                               'cust_branch' => array('contact_name', 'disable_trans'),
-               );
-
-               foreach($dropcol as $table => $columns)
-                       foreach($columns as $col) {
-                               if (db_query("ALTER TABLE `".TB_PREF."{$table}` DROP `$col`")==false) {
-                                       display_error("Cannot drop {$table}.{$col} column:<br>".db_error_msg($db));
-                                       return false;
-                               }
-                       }
-
-               return  update_company_prefs(array('version_id'=>$db_version));
-       }
-       //
-       //      Checking before install
-       //
-       function pre_check($pref, $force)
-       {
-               return true;
+               return $result;
        }
 
        //
        // optional procedure done after upgrade fail, before backup is restored
        //
-       function post_fail($pref)
+       function post_fail($company)
        {
+               $pref = $this->companies[$company]['tbpref'];
                db_query("DROP TABLE IF EXISTS " . $pref . 'wo_costing');
        }
-       //
-       //      Test if patch was applied before.
-       //
-       function installed($pref)
-       {
-               $n = 2; // number of patches to be installed
-               $patchcnt = 0;
-
-               if (!check_table($pref, 'suppliers', 'tax_algorithm')) $patchcnt++;
-               if (!check_table($pref, 'wo_costing')) $patchcnt++;
-               return $n == $patchcnt ? true : ($patchcnt ? ($patchcnt.'/'. $n) : 0);
-       }
 
        function update_workorders()
        {
@@ -102,11 +130,8 @@ class fa2_4 {
                ." AND person_type_id=1";
                $res = db_query($sql);
                if (!$res)
-               {
-                       display_error("Cannot update work orders costs"
-                               .':<br>'. db_error_msg($db));
-                       return false;
-               }
+                       return $this->log_error(sprintf(_("Cannot update work orders costs:\n%s"), db_error_msg($db)));
+
                while ($row = db_fetch($res))
                {
                        $journal_id = get_next_trans_no(ST_JOURNAL);
@@ -116,7 +141,7 @@ class fa2_4 {
                                WHERE `type`=".ST_WORKORDER." AND type_no={$row['type_no']} AND tran_date='{$row['tran_date']}'
                                AND person_id='{$row['person_id']}'";
                        if (!db_query($sql1)) return false;
-                       
+
                        $sql2 = "INSERT INTO ".TB_PREF."wo_costing (workorder_id, cost_type, trans_no) 
                                VALUES ({$row['type_no']}, {$row['person_id']}, {$journal_id})";
                        if (!db_query($sql2)) return false;
@@ -135,9 +160,9 @@ class fa2_4 {
        . for all text/char column:
         - suppress autorecoding by change of the type to related binary/blob type
         - change column to utf8 encodding and selected collation.
-       . change default table encoding to utf8
+       . change default table encoding to utf8 and selected collation
 */
-       function switch_database_to_utf($pref, $test = false) {
+       function switch_database_to_utf($pref, $dbg = false) {
 
                global $installed_languages, $dflt_lang;
 
@@ -147,9 +172,8 @@ class fa2_4 {
                $lang = array_search_value($dflt_lang, $installed_languages, 'code');
                $new_encoding = get_mysql_encoding_name(strtoupper($lang['encoding']));
 
-               if ($test)
-                       error_log('Switching database to utf8 encoding from '.$old_encoding);
-               $collation = get_mysql_collation();
+               $this->log_error(sprintf('Switching database to utf8 encoding from %s', $old_encoding), 'Info');
+               $collation = $this->collation;
                $tsql = "SHOW TABLES LIKE '".($pref=='' ? '' : substr($pref, 0, -1).'\\_')."%'";
                $tresult = db_query($tsql, "Cannot select all tables with prefix '$pref'");
                while($tbl = db_fetch($tresult)) {
@@ -170,8 +194,8 @@ class fa2_4 {
 
                                if ($bintype != $col['Type'])
                                { // this is char/text column, so change encoding to proper encoding
-                                       if ($test)
-                                               error_log($table.'.'.$col['Field']);
+                                       if ($dbg)
+                                               $this->log_error(sprintf('%s switched to uft8.', $table.'.'.$col['Field']), 'Debug');
 
                                        $null = $col['Null'] === 'YES' ? ' NULL ' : ' NOT NULL ';
                                        $default = $col['Null'] !== 'YES' && isset($col['Default']) ? ' DEFAULT '.db_escape($col['Default']) : '';
@@ -196,8 +220,7 @@ class fa2_4 {
                        db_query("ALTER TABLE `$table` COLLATE $collation");
                }
                db_query("ALTER DATABASE COLLATE $collation");
-               if ($test)
-                       error_log('Convertion to utf8 done.');
+               $this->log_error(_('Convertion to utf8 done.'), 'Info');
 
                return true;
        }
@@ -221,19 +244,24 @@ class fa2_4 {
 
        function do_cleanup()
        {
+               global $db;
+
+               //remove obsolete and temporary columns.
+               // this have to be done here as db_import rearranges alter query order
                $dropcol = array(
                                'tax_group_items' => array('rate'),
                                'budget_trans' => array('type', 'type_no', 'person_id', 'person_type_id', 'memo_'),
+                               'cust_branch' => array('contact_name', 'disable_trans'),
                );
 
                foreach($dropcol as $table => $columns)
                        foreach($columns as $col) {
                                if (db_query("ALTER TABLE `".TB_PREF."{$table}` DROP `$col`") == false) {
-                                       display_error("Cannot drop {$table}.{$col} column:<br>".db_error_msg($db));
-                                       return false;
+                                       return $this->log_error(sprintf(_("Cannot drop column in %s table: %s"), $table, db_error_msg($db)));
                                }
                        }
-       }
+               return true;
+  }
 }
 
 $install = new fa2_4;
diff --git a/themes/aqua/images/log.png b/themes/aqua/images/log.png
new file mode 100644 (file)
index 0000000..ef03a4d
Binary files /dev/null and b/themes/aqua/images/log.png differ
diff --git a/themes/cool/images/log.png b/themes/cool/images/log.png
new file mode 100644 (file)
index 0000000..ef03a4d
Binary files /dev/null and b/themes/cool/images/log.png differ
diff --git a/themes/default/images/log.png b/themes/default/images/log.png
new file mode 100644 (file)
index 0000000..ef03a4d
Binary files /dev/null and b/themes/default/images/log.png differ