/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 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         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * This file implements classes SKGDocumentBank.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgdocumentbank.h"

#include <KLocale>
#include <KGlobal>
#include <KIcon>

#include <QSqlDatabase>
#include <QDBusConnection>

#include <cmath>

#include "skgbankobject.h"
#include "skgaccountobject.h"
#include "skgunitobject.h"
#include "skgunitvalueobject.h"
#include "skgreportbank.h"
#include "skgtraces.h"
#include "skgerror.h"
#include "skgservices.h"
#include "skgtransactionmng.h"

SKGDocumentBank::SKGDocumentBank() : SKGDocument(), m_computeBalances(true)
{
    SKGTRACEINFUNC(10);
    connect(this, SIGNAL(tableModified(QString,int,bool)), this, SLOT(refreshCache(QString)));

    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject("/skrooge/skgdocumentbank", this, QDBusConnection::ExportAllContents);

    // Initialisation of not undoable tables
    SKGListNotUndoable.push_back("T.operationbalance");
    SKGListNotUndoable.push_back("T.budgetsuboperation");
}

SKGDocumentBank::~SKGDocumentBank()
{
    SKGTRACEINFUNC(10);
}

SKGError SKGDocumentBank::computeBudgetSuboperationLinks()
{
    SKGError err;
    SKGTRACEINFUNCRC(5, err);
    // Remove computed values
    err = this->executeSqliteOrder("DELETE FROM budgetsuboperation");

    // Compute values
    IFOKDO(err, executeSqliteOrder(
               "INSERT INTO budgetsuboperation (id, id_suboperation, i_priority) "

               // Garbage collector annualy
               "SELECT b.id, s.id, 6 FROM budget b, operation o, suboperation s WHERE +s.rd_operation_id=o.id AND b.rc_category_id=0 AND b.i_month=0 AND b.i_year=STRFTIME('%Y', o.d_date)"

               // Garbage collectory monthly
               " UNION SELECT b.id, s.id, 5 FROM budget b, operation o, suboperation s WHERE +s.rd_operation_id=o.id AND  b.rc_category_id=0 AND b.i_month<>0 AND b.i_year=STRFTIME('%Y', o.d_date) AND b.i_month=STRFTIME('%m', o.d_date)"

               // Garbage categories annualy
               " UNION SELECT b.id, s.id, 4 FROM budget b, operation o, v_suboperation_display s WHERE +s.rd_operation_id=o.id AND b.rc_category_id<>0 AND b.i_month=0 AND b.i_year=STRFTIME('%Y', o.d_date) AND b.t_including_subcategories='Y' AND s.t_CATEGORY LIKE (SELECT c2.t_fullname FROM category c2 WHERE c2.id=b.rc_category_id)||'" % OBJECTSEPARATOR % "%'"

               // Garbage categories monthly
               " UNION SELECT b.id, s.id, 3 FROM budget b, operation o, v_suboperation_display s WHERE +s.rd_operation_id=o.id AND b.rc_category_id<>0 AND b.i_month<>0 AND b.i_year=STRFTIME('%Y', o.d_date) AND b.i_month=STRFTIME('%m', o.d_date) AND b.t_including_subcategories='Y' AND s.t_CATEGORY LIKE (SELECT c2.t_fullname FROM category c2 WHERE c2.id=b.rc_category_id)||'" % OBJECTSEPARATOR % "%'"

               // Strict category annualy
               " UNION SELECT b.id, s.id, 2 FROM budget b, operation o, v_suboperation_display s WHERE +s.rd_operation_id=o.id AND b.rc_category_id<>0 AND b.i_month=0 AND b.i_year=STRFTIME('%Y', o.d_date) AND b.rc_category_id=s.r_category_id"

               // Strict category monthly
               " UNION SELECT b.id, s.id, 1 FROM budget b, operation o, v_suboperation_display s WHERE +s.rd_operation_id=o.id AND b.rc_category_id<>0 AND b.i_month<>0 AND b.i_year=STRFTIME('%Y', o.d_date) AND b.i_month=STRFTIME('%m', o.d_date) AND +b.rc_category_id=s.r_category_id"));
    // Remove useless values
    IFOKDO(err, executeSqliteOrder("DELETE FROM budgetsuboperation WHERE EXISTS (SELECT 1 FROM budgetsuboperation b2 WHERE b2.id_suboperation=budgetsuboperation.id_suboperation AND b2.i_priority<budgetsuboperation.i_priority)"));

    return err;
}

void SKGDocumentBank::setComputeBalances(bool iEnabled)
{
    if (iEnabled != m_computeBalances) {
        m_computeBalances = iEnabled;
        computeBalances();
    }
}

SKGError SKGDocumentBank::computeBalances()
{
    SKGError err;
    SKGTRACEINFUNCRC(5, err);
    // Remove computed values
    err = this->executeSqliteOrder("DELETE FROM operationbalance");

    if (m_computeBalances) {
        SKGStringListList result;
        IFOKDO(err, executeSelectSqliteOrder("SELECT id, rd_account_id, f_CURRENTAMOUNT, f_QUANTITY FROM v_operation WHERE t_template='N' ORDER BY rd_account_id, d_date, id", result))
        int nb = result.count();
        double sum = 0;
        double sum2 = 0;
        int currentAccount = 0;
        QStringList items;
        for (int i = 1; !err && i < nb; ++i) {  // Ignore header
            QStringList line = result.at(i);
            QString idOp = line.at(0);
            int account = SKGServices::stringToInt(line.at(1));
            double val = SKGServices::stringToDouble(line.at(2));
            double val2 = SKGServices::stringToDouble(line.at(3));

            if (account != currentAccount) {
                sum = 0;
                sum2 = 0;
                currentAccount = account;
            }

            sum += val;
            sum2 += val2;

            items.push_back(idOp % "," % SKGServices::doubleToString(sum) % "," % SKGServices::doubleToString(sum2));

            if (items.count() == 490) {
                err = this->executeSqliteOrder("INSERT INTO operationbalance (r_operation_id,f_balance,f_balance_entered) "
                                               "SELECT  " % items.join(" UNION SELECT "));
                items.clear();
            }
        }
        if (!err && items.count()) err = this->executeSqliteOrder("INSERT INTO operationbalance (r_operation_id,f_balance,f_balance_entered) "
                                             "SELECT  " % items.join(" UNION SELECT "));
    }
    return err;
}

SKGError SKGDocumentBank::endTransaction(bool succeedded)
{
    SKGError err;
    if (succeedded && getDepthTransaction() == 1) {
        if (getCachedValue("SKG_REFRESH_VIEW") == "Y") {
            QStringList listModifiedTables;
            err = this->getDistinctValues("doctransactionitem",
                                          "t_object_table",
                                          "rd_doctransaction_id=0",
                                          listModifiedTables);
            if (!err &&
                (listModifiedTables.contains("operation") || listModifiedTables.contains("suboperation") || listModifiedTables.contains("unit") || listModifiedTables.contains("unitvalue"))
               ) {
                // Computation of cache
                err = computeBalances();
            }

            if (!err &&
                (listModifiedTables.contains("operation") || listModifiedTables.contains("suboperation") || listModifiedTables.contains("unit") || listModifiedTables.contains("unitvalue") || listModifiedTables.contains("category") || listModifiedTables.contains("budget"))
               ) {
                // Computation of cache
                err = computeBudgetSuboperationLinks();
            }
        }
        // Clean main variations cache
        m_5mainVariations_cache.clear();
        m_5mainVariationsCat_cache.clear();
        m_5mainVariations_inputs = "";
    }

    SKGError err2 = SKGDocument::endTransaction(succeedded);
    if (!err && err2) {
        err = err2;
    }
    return err;
}

QString SKGDocumentBank::getViewsIndexesAndTriggersVersion()
{
    return "2015.04.28_" % getParameter("SKG_LANGUAGE");
}

SKGError SKGDocumentBank::refreshViewsIndexesAndTriggers(bool iForce)
{
    SKGError err;
    SKGTRACEINFUNCRC(5, err);

    QString version = getParameter("SKG_DB_BANK_VIEWS_VERSION");
    if (!iForce && version == getViewsIndexesAndTriggersVersion()) {
        return err;
    }

    err = setParameter("SKG_DB_BANK_VIEWS_VERSION", getViewsIndexesAndTriggersVersion());

    QString dateFormatShort = "%Y-%m-%d";
    KLocale* loc = KGlobal::locale();
    bool negativePrefixCurrencySymbol = false;
    if (loc) {
        dateFormatShort = loc->dateFormatShort();
        negativePrefixCurrencySymbol = loc->negativePrefixCurrencySymbol();
    }

    // WARNING: Don't forget to update getViewVersion when this methode is modified
    /**
     * This constant is used to initialized the data model (trigger creation)
     * IF YOU MODIFY THIS METHOD, DO NOT FORGET TO MODIFY getViewsIndexesAndTriggersVersion TOO
     */
    QStringList BankInitialDataModelTrigger;
    BankInitialDataModelTrigger DELETECASCADEPARAMETER("bank")
    DELETECASCADEPARAMETER("account")
    DELETECASCADEPARAMETER("unit")
    DELETECASCADEPARAMETER("unitvalue")
    DELETECASCADEPARAMETER("category")
    DELETECASCADEPARAMETER("operation")
    DELETECASCADEPARAMETER("interest")
    DELETECASCADEPARAMETER("suboperation")
    DELETECASCADEPARAMETER("refund")
    DELETECASCADEPARAMETER("payee")
    DELETECASCADEPARAMETER("recurrentoperation")
    DELETECASCADEPARAMETER("rule")
    DELETECASCADEPARAMETER("budget")
    DELETECASCADEPARAMETER("budgetrule")


    // Compute fullname
            << "DROP TRIGGER IF EXISTS cpt_category_fullname3"
            /* << "CREATE TRIGGER cpt_category_fullname1 " // This trigger must be the first
             "AFTER UPDATE OF t_fullname ON category BEGIN "
             "UPDATE category SET t_name=t_name WHERE rd_category_id=new.id;"
             "END"*/

            << "DROP TRIGGER IF EXISTS cpt_category_fullname1"
            << "CREATE TRIGGER cpt_category_fullname1 "
            "AFTER INSERT ON category BEGIN "
            "UPDATE category SET t_fullname="
            "CASE WHEN rd_category_id IS NULL OR rd_category_id='' OR rd_category_id=0 THEN new.t_name ELSE (SELECT c.t_fullname FROM category c WHERE c.id=new.rd_category_id)||'" % OBJECTSEPARATOR % "'||new.t_name END "
            "WHERE id=new.id;"
            "END"

            << "DROP TRIGGER IF EXISTS cpt_category_fullname2"
            << "CREATE TRIGGER cpt_category_fullname2 "
            "AFTER UPDATE OF t_name, rd_category_id ON category BEGIN "
            "UPDATE category SET t_fullname="
            "CASE WHEN rd_category_id IS NULL OR rd_category_id='' OR rd_category_id=0 THEN new.t_name ELSE (SELECT c.t_fullname FROM category c WHERE c.id=new.rd_category_id)||'" % OBJECTSEPARATOR % "'||new.t_name END "
            "WHERE id=new.id;"
            "UPDATE category SET t_name=t_name WHERE rd_category_id=new.id;"
            "END"

            // -- Reparent suboperation on parent category when a category is removed
            << "DROP TRIGGER IF EXISTS fkdc_category_delete"
            << "CREATE TRIGGER fkdc_category_delete "
            "BEFORE DELETE ON category "
            "FOR EACH ROW BEGIN "
            "    UPDATE suboperation SET r_category_id=OLD.rd_category_id WHERE r_category_id IN (SELECT c.id FROM category c WHERE c.id=OLD.id OR c.t_fullname LIKE OLD.t_fullname||'" % OBJECTSEPARATOR % "%'); "
            "END "

            << "DROP TRIGGER IF EXISTS fkdc_category_parent_id_category_id"

            // Trigger for update on view
            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_i_tmp"
            << "CREATE TRIGGER trgu_v_operation_prop_i_tmp "
            "INSTEAD OF UPDATE OF i_tmp ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    UPDATE suboperation SET i_tmp=NEW.i_tmp WHERE id=OLD.i_SUBOPID; "
            "    UPDATE operation SET i_tmp=NEW.i_tmp WHERE id=OLD.i_OPID; "
            "    UPDATE parameters SET i_tmp=NEW.i_tmp WHERE id=OLD.i_PROPPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_t_realcomment"
            << "CREATE TRIGGER trgu_v_operation_prop_t_realcomment "
            "INSTEAD OF UPDATE OF t_REALCOMMENT ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    UPDATE suboperation SET t_comment=NEW.t_REALCOMMENT WHERE id=OLD.i_SUBOPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_t_unit"
            << "CREATE TRIGGER trgu_v_operation_prop_t_unit "
            "INSTEAD OF UPDATE OF t_UNIT ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    INSERT OR IGNORE INTO unit (t_name, t_symbol) VALUES (NEW.t_UNIT, NEW.t_UNIT); "
            "    UPDATE operation set rc_unit_id=(SELECT id FROM unit WHERE t_name=NEW.t_UNIT) WHERE id=OLD.i_OPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_t_account"
            << "CREATE TRIGGER trgu_v_operation_prop_t_account "
            "INSTEAD OF UPDATE OF t_ACCOUNT ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    INSERT OR IGNORE INTO account (t_name, rd_bank_id) VALUES (NEW.t_ACCOUNT, (SELECT MIN(id) FROM bank)); "
            "    UPDATE operation set rd_account_id=(SELECT id FROM account WHERE t_name=NEW.t_ACCOUNT) WHERE id=OLD.i_OPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_t_payee"
            << "CREATE TRIGGER trgu_v_operation_prop_t_payee "
            "INSTEAD OF UPDATE OF t_PAYEE ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    INSERT OR IGNORE INTO payee (t_name) VALUES (NEW.t_PAYEE); "
            "    UPDATE operation set r_payee_id=(SELECT id FROM payee WHERE t_name=NEW.t_PAYEE) WHERE id=OLD.i_OPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_t_realrefund"
            << "CREATE TRIGGER trgu_v_operation_prop_t_realrefund "
            "INSTEAD OF UPDATE OF t_REALREFUND ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    INSERT OR IGNORE INTO refund (t_name) VALUES (NEW.t_REALREFUND); "
            "    UPDATE suboperation set r_refund_id=(SELECT id FROM refund WHERE t_name=NEW.t_REALREFUND) WHERE id=OLD.i_SUBOPID; "
            "END "

            << "DROP TRIGGER IF EXISTS trgu_v_operation_prop_d_dateop"
            << "CREATE TRIGGER trgu_v_operation_prop_d_dateop "
            "INSTEAD OF UPDATE OF d_DATEOP ON v_operation_prop "
            "FOR EACH ROW BEGIN "
            "    UPDATE suboperation set d_date=date(d_date, '+'||(julianday(NEW.d_DATEOP)-julianday(old.d_DATEOP))||' days') WHERE id=OLD.i_SUBOPID; "
            "    UPDATE operation set d_date=NEW.d_DATEOP WHERE id=OLD.i_OPID; "
            "END ";

    // Build triggers for normal attribute
    SKGServices::SKGAttributesList attributes;
    getAttributesDescription("operation", attributes);
    int nb = attributes.count();
    for (int i = 0; i < nb; ++i) {
        QString att = attributes[i].name;
        if (att == att.toLower() && att != "i_tmp") {
            BankInitialDataModelTrigger << QString("DROP TRIGGER IF EXISTS trgu_v_operation_prop_") % att
                                        << "CREATE TRIGGER trgu_v_operation_prop_" % att % " "
                                        "INSTEAD OF UPDATE OF " % att % " ON v_operation_prop "
                                        "FOR EACH ROW BEGIN "
                                        "    UPDATE operation SET " % att % "=NEW." % att % " WHERE id=OLD.i_OPID; "
                                        "END ";
        }
    }
    /**
     * This constant is used to initialized the data model (index creation)
     */
    QStringList BankInitialDataModelIndex;
    BankInitialDataModelIndex << "CREATE UNIQUE INDEX uidx_unit_name ON unit(t_name)"
                              << "CREATE UNIQUE INDEX uidx_unit_symbol ON unit(t_symbol)"

                              << "CREATE INDEX idx_unit_unit_id ON unitvalue(rd_unit_id)"
                              << "CREATE UNIQUE INDEX uidx_unitvalue ON unitvalue(d_date,rd_unit_id)"
                              << "CREATE UNIQUE INDEX uidx_unitvalue2 ON unitvalue(rd_unit_id, d_date)"

                              << "CREATE UNIQUE INDEX uidx_bank_name ON bank(t_name)"

                              << "CREATE UNIQUE INDEX uidx_account_name ON account(t_name)"
                              << "CREATE INDEX idx_account_bank_id ON account(rd_bank_id)"
                              << "CREATE INDEX idx_account_type ON account(t_type)"

                              << "CREATE INDEX idx_category_category_id ON category(rd_category_id)"
                              << "CREATE INDEX idx_category_t_fullname ON category(t_fullname)"
                              << "CREATE UNIQUE INDEX uidx_category_parent_id_name ON category(t_name,rd_category_id)"

                              << "CREATE INDEX  idx_operation_tmp1_found_transfert ON operation (rc_unit_id, d_date)"
                              << "CREATE INDEX  idx_operation_grouped_operation_id ON operation (i_group_id)"
                              // << "CREATE INDEX  idx_operation_t_mode ON operation (t_mode)"
                              // << "CREATE INDEX  idx_operation_t_payee ON operation (t_payee)"
                              << "CREATE INDEX  idx_operation_i_number ON operation (i_number)"
                              << "CREATE INDEX  idx_operation_i_tmp ON operation (i_tmp)"
                              << "CREATE INDEX  idx_operation_rd_account_id ON operation (rd_account_id)"
                              << "CREATE INDEX  idx_operation_rd_account_id_t_imported ON operation (rd_account_id, t_imported)"
                              << "CREATE INDEX  idx_operation_rd_account_id_i_number ON operation (rd_account_id, i_number)"
                              << "CREATE INDEX  idx_operation_rc_unit_id ON operation (rc_unit_id)"
                              << "CREATE INDEX  idx_operation_t_status ON operation (t_status)"
                              << "CREATE INDEX  idx_operation_t_import_id ON operation (t_import_id)"
                              << "CREATE INDEX  idx_operation_d_date ON operation (d_date)"
                              << "CREATE INDEX  idx_operation_t_template ON operation (t_template)"

                              << "CREATE INDEX  idx_operationbalance_operation_id ON operationbalance (r_operation_id)"

                              << "CREATE INDEX idx_suboperation_operation_id ON suboperation (rd_operation_id)"
                              << "CREATE INDEX idx_suboperation_i_tmp ON suboperation (i_tmp)"
                              << "CREATE INDEX idx_suboperation_category_id ON suboperation (r_category_id)"
                              << "CREATE INDEX idx_suboperation_refund_id_id ON suboperation (r_refund_id)"

                              << "CREATE INDEX  idx_recurrentoperation_rd_operation_id ON recurrentoperation (rd_operation_id)"

                              << "CREATE UNIQUE INDEX uidx_refund_name ON refund(t_name)"
                              << "CREATE INDEX idx_refund_close ON refund(t_close)"

                              << "CREATE UNIQUE INDEX uidx_payee_name ON payee(t_name)"

                              << "CREATE INDEX  idx_interest_account_id ON interest (rd_account_id)"
                              << "CREATE UNIQUE INDEX uidx_interest ON interest(d_date,rd_account_id)"

                              << "CREATE INDEX idx_rule_action_type ON rule(t_action_type)"

                              << "CREATE UNIQUE INDEX uidx_budget ON budget(i_year,i_month, rc_category_id)"
                              << "CREATE INDEX idx_budget_category_id ON budget(rc_category_id)"
                              << "CREATE INDEX idx_budgetsuboperation_id ON budgetsuboperation (id)"
                              << "CREATE INDEX idx_budgetsuboperation_id_suboperation ON budgetsuboperation (id_suboperation)";

    /**
     * This constant is used to initialized the data model (view creation)
     */
    QStringList BankInitialDataModelView;
    BankInitialDataModelView
    // ==================================================================
    // These following views contains only attributes used by corresponding class (better for performances)
    // unit
            << "CREATE VIEW  v_unit_displayname AS "
            "SELECT *, t_name||' ('||t_symbol||')' AS t_displayname FROM unit"

            << "CREATE VIEW  v_unit_tmp1 AS "
            "SELECT *,"
            "(SELECT COUNT(1) FROM unitvalue s WHERE s.rd_unit_id=unit.id) AS i_NBVALUES, "
            "(CASE WHEN unit.rd_unit_id=0 THEN '' ELSE (SELECT (CASE WHEN s.t_symbol!='' THEN s.t_symbol ELSE s.t_name END) FROM unit s WHERE s.id=unit.rd_unit_id) END) AS t_UNIT,"
            "(CASE unit.t_type "
            "WHEN '1' THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Primary currency")) % "' "
            "WHEN '2' THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Secondary currency")) % "' "
            "WHEN 'C' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a country's currency", "Currency")) % "' "
            "WHEN 'S' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a financial share, as in a stock market", "Share")) % "' "
            "WHEN 'I' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a financial index like the Dow Jones, NASDAQ, CAC40...", "Index")) % "' "
            "ELSE '" % SKGServices::stringToSqlString(i18nc("Noun, a physical object like a house or a car", "Object")) % "' END) AS t_TYPENLS, "
            "(SELECT MIN(s.d_date) FROM  unitvalue s WHERE s.rd_unit_id=unit.id) AS d_MINDATE, "
            "(SELECT MAX(s.d_date) FROM  unitvalue s WHERE s.rd_unit_id=unit.id) AS d_MAXDATE "
            "FROM unit"

            << "CREATE VIEW  v_unit_tmp2 AS "
            "SELECT *,"
            "CASE WHEN v_unit_tmp1.t_type='1' THEN 1 ELSE IFNULL((SELECT s.f_quantity FROM unitvalue s INDEXED BY uidx_unitvalue2 WHERE s.rd_unit_id=v_unit_tmp1.id AND s.d_date=v_unit_tmp1.d_MAXDATE),1) END AS f_LASTVALUE "
            "FROM v_unit_tmp1"

            << "CREATE VIEW  v_unit AS "
            "SELECT *,"
            "v_unit_tmp2.f_LASTVALUE*IFNULL((SELECT s2.f_LASTVALUE FROM v_unit_tmp2 s2 WHERE s2.id=v_unit_tmp2.rd_unit_id) , 1) AS f_CURRENTAMOUNT "
            "FROM v_unit_tmp2"

            // unitvalue
            << "CREATE VIEW  v_unitvalue_displayname AS "
            "SELECT *, (SELECT t_displayname FROM v_unit_displayname WHERE unitvalue.rd_unit_id=v_unit_displayname.id)||' '||IFNULL(STRFTIME('" % dateFormatShort % "',d_date),STRFTIME('%Y-%m-%d',d_date)) AS t_displayname FROM unitvalue"

            << "CREATE VIEW  v_unitvalue AS "
            "SELECT * "
            "FROM unitvalue"

            // suboperation
            << "CREATE VIEW  v_suboperation AS "
            "SELECT * "
            "FROM suboperation"

            // operation
            << "CREATE VIEW  v_operation_numbers AS "
            "SELECT DISTINCT i_number, rd_account_id FROM operation"

            << "CREATE VIEW  v_operation_next_numbers AS "
            "SELECT T1.i_number+1 AS i_number, T1.rd_account_id FROM v_operation_numbers AS T1 LEFT OUTER JOIN v_operation_numbers T2 "
            "ON T2.rd_account_id=T1.rd_account_id AND T2.i_number=T1.i_number+1 "
            "WHERE T1.i_number!=0 AND (T2.i_number IS NULL) ORDER BY T1.i_number"

            << "CREATE VIEW  v_operation_tmp1 AS "
            "SELECT operation.*,"
            "(CASE WHEN v_unit.t_symbol!='' THEN v_unit.t_symbol ELSE v_unit.t_name END) AS t_UNIT,"
            "IFNULL((SELECT s.t_name FROM payee s WHERE s.id=operation.r_payee_id), '') AS t_PAYEE,"
            "v_unit.i_nbdecimal AS i_NBDEC,"
            "v_unit.t_type AS t_TYPEUNIT,"
            "v_unit.f_CURRENTAMOUNT AS f_CURRENTAMOUNTUNIT,"
            "(SELECT TOTAL(s.f_value) FROM suboperation s WHERE s.rd_operation_id=operation.ID) AS f_QUANTITY,"
            "(SELECT COUNT(1) FROM suboperation s WHERE s.rd_operation_id=operation.ID) AS i_NBSUBOPERATIONS, "
            "account.t_name AS t_ACCOUNT, "
            "account.t_type AS t_TYPEACCOUNT, "
            "bank.t_name AS t_BANK "
            "FROM operation, account, bank, v_unit WHERE +operation.rd_account_id=account.id AND +account.rd_bank_id=bank.id AND +operation.rc_unit_id=v_unit.id"

            << "CREATE VIEW  v_operation AS "
            "SELECT *,"
            "(SELECT s.id FROM suboperation s WHERE s.rd_operation_id=v_operation_tmp1.id AND ABS(s.f_value)=(SELECT MAX(ABS(s2.f_value)) FROM suboperation s2 WHERE s2.rd_operation_id=v_operation_tmp1.id)) AS i_MOSTIMPSUBOP,"
            "v_operation_tmp1.f_CURRENTAMOUNTUNIT*v_operation_tmp1.f_QUANTITY AS f_CURRENTAMOUNT, "
            "(CASE WHEN v_operation_tmp1.i_group_id<>0 AND v_operation_tmp1.t_TYPEACCOUNT<>'L' AND v_operation_tmp1.t_TYPEUNIT IN ('1', '2', 'C') AND "
            "(SELECT COUNT(1) FROM operation WHERE i_group_id=v_operation_tmp1.i_group_id)=2 AND "
            "EXISTS (SELECT 1 FROM v_operation_tmp1 op2 WHERE op2.i_group_id=v_operation_tmp1.i_group_id "
            "AND op2.t_TYPEACCOUNT<>'L' AND op2.t_TYPEUNIT IN ('1', '2', 'C') AND op2.f_QUANTITY*v_operation_tmp1.f_QUANTITY<=0) THEN 'Y' ELSE 'N' END) AS t_TRANSFER "
//        "ROUND((SELECT s.f_CURRENTAMOUNT FROM v_unit s WHERE s.id=v_operation_tmp1.rc_unit_id)*v_operation_tmp1.f_QUANTITY, 2) AS f_CURRENTAMOUNT "
            "FROM v_operation_tmp1"

            << "CREATE VIEW  v_operation_displayname AS "
            "SELECT *, IFNULL(STRFTIME('" % dateFormatShort % "',d_date),STRFTIME('%Y-%m-%d',d_date))||' '||IFNULL(t_PAYEE,'')||' '||"
            % (negativePrefixCurrencySymbol ? "(SELECT (CASE WHEN s.t_symbol!='' THEN s.t_symbol ELSE s.t_name END) FROM unit s WHERE s.id=v_operation.rc_unit_id)||' '||" : "") %
            "ROUND(v_operation.f_CURRENTAMOUNT,2)||(CASE WHEN ROUND(v_operation.f_CURRENTAMOUNT,2) LIKE '%._' THEN '0' ELSE '' END) "
            % (!negativePrefixCurrencySymbol ? "||' '||(SELECT (CASE WHEN s.t_symbol!='' THEN s.t_symbol ELSE s.t_name END) FROM unit s WHERE s.id=v_operation.rc_unit_id)" : "") %
            " AS t_displayname FROM v_operation"

            << "CREATE VIEW  v_operation_delete AS "
            "SELECT *, (CASE WHEN t_status='Y' THEN '" %
            SKGServices::stringToSqlString(i18nc("Error message",  "You are not authorized to delete this operation because in \"checked\" status")) %
            "' END) t_delete_message FROM operation"

            // account
            << "CREATE VIEW  v_account AS "
            "SELECT "
            "account.*,"
            "bank.t_name  AS t_BANK,"
            "bank.t_bank_number AS t_BANK_NUMBER,"
            "bank.t_icon AS t_ICON,"
            "(SELECT MAX(s.d_date) FROM  interest s WHERE s.rd_account_id=account.id) AS d_MAXDATE "
            "FROM account, bank WHERE +account.rd_bank_id=bank.id"

            << "CREATE VIEW  v_account_amount AS "
            "SELECT "
            "v_account.*,"
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_operation s WHERE s.rd_account_id=v_account.id AND s.t_template='N') AS f_CURRENTAMOUNT "
            "FROM v_account"

            << "CREATE VIEW  v_account_delete AS "
            "SELECT *, (CASE WHEN EXISTS(SELECT 1 FROM operation WHERE rd_account_id=account.id AND d_date<>'0000-00-00' AND t_template='N' AND t_status='Y') THEN '" %
            SKGServices::stringToSqlString(i18nc("Error message",  "You are not authorized to delete this account because it contains some checked operations")) %
            "' END) t_delete_message FROM account"

            // bank
            << "CREATE VIEW  v_bank_displayname AS "
            "SELECT *, t_name AS t_displayname FROM bank"

            << "CREATE VIEW  v_account_displayname AS "
            "SELECT *, (SELECT t_displayname FROM v_bank_displayname WHERE account.rd_bank_id=v_bank_displayname.id)||'-'||t_name AS t_displayname FROM account"

            << "CREATE VIEW  v_bank AS "
            "SELECT * FROM bank"

            << "CREATE VIEW  v_bank_amount AS "
            "SELECT *,"
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_account_amount s WHERE s.rd_bank_id=v_bank.id) AS f_CURRENTAMOUNT "
            "FROM v_bank"

            // category
            << "CREATE VIEW  v_category_displayname AS "
            "SELECT *, t_fullname AS t_displayname FROM category"

            << "CREATE VIEW  v_category AS SELECT * "
            "FROM category"

            // recurrentoperation
            << "CREATE VIEW  v_recurrentoperation AS "
            "SELECT *,"
            "date(d_date, '-'||((CASE t_period_unit WHEN 'W' THEN 7  ELSE 1 END)*i_period_increment)||' '||(CASE t_period_unit WHEN 'M' THEN 'month' WHEN 'Y' THEN 'year' ELSE 'day' END)) as d_PREVIOUS,"
            "i_period_increment||' '||(CASE t_period_unit "
            "WHEN 'Y' THEN '" % SKGServices::stringToSqlString(i18nc("Noun",  "year(s)")) % "' "
            "WHEN 'M' THEN '" % SKGServices::stringToSqlString(i18nc("Noun",  "month(s)")) % "' "
            "WHEN 'W' THEN '" % SKGServices::stringToSqlString(i18nc("Noun",  "week(s)")) % "' "
            "ELSE '" % SKGServices::stringToSqlString(i18nc("Noun",  "day(s)")) % "' END) AS t_PERIODNLS "
            "FROM recurrentoperation"

            << "CREATE VIEW  v_recurrentoperation_displayname AS "
            "SELECT *, IFNULL(STRFTIME('" % dateFormatShort % "',d_date),STRFTIME('%Y-%m-%d',d_date))||' '||SUBSTR((SELECT t_displayname FROM v_operation_displayname WHERE v_operation_displayname.id=v_recurrentoperation.rd_operation_id), 11) AS t_displayname FROM v_recurrentoperation"

            // ==================================================================
            // These following views contains all attributes needed for display
            // unitvalue
            << "CREATE VIEW  v_unitvalue_display AS "
            "SELECT *,"
            "IFNULL((SELECT (CASE WHEN s.t_symbol!='' THEN s.t_symbol ELSE s.t_name END) FROM unit s WHERE s.id=(SELECT s2.rd_unit_id FROM unit s2 WHERE s2.id=unitvalue.rd_unit_id)),'') AS t_UNIT,"
            "STRFTIME('%Y-%m',unitvalue.d_date) AS d_DATEMONTH,"
            "STRFTIME('%Y',unitvalue.d_date) AS d_DATEYEAR "
            "FROM unitvalue"

            // suboperation
            << "CREATE VIEW  v_suboperation_display AS "
            "SELECT *,"
            "IFNULL((SELECT s.t_fullname FROM category s WHERE s.id=v_suboperation.r_category_id),'') AS t_CATEGORY, "
            "IFNULL((SELECT s.t_name FROM refund s WHERE s.id=v_suboperation.r_refund_id),'') AS t_REFUND, "
            "(CASE WHEN v_suboperation.f_value>=0 THEN v_suboperation.f_value ELSE 0 END) AS f_VALUE_INCOME, "
            "(CASE WHEN v_suboperation.f_value<=0 THEN v_suboperation.f_value ELSE 0 END) AS f_VALUE_EXPENSE "
            "FROM v_suboperation"

            << "CREATE VIEW  v_suboperation_displayname AS "
            "SELECT *, t_CATEGORY||' : '||f_value AS t_displayname FROM v_suboperation_display"

            // operation
            << "CREATE VIEW  v_operation_display_all AS "
            "SELECT *,"
            // "(SELECT s.t_comment FROM v_suboperation_display s WHERE s.id=v_operation.i_MOSTIMPSUBOP) AS t_COMMENT,"
            "IFNULL((CASE WHEN v_operation.i_group_id=0 THEN '' ELSE (SELECT GROUP_CONCAT(DISTINCT(op2.t_ACCOUNT)) FROM v_operation_tmp1 op2 WHERE op2.i_group_id=v_operation.i_group_id AND op2.id<>v_operation.id) END), '') AS t_TOACCOUNT, "
            "(SELECT s.t_CATEGORY FROM v_suboperation_display s WHERE s.id=v_operation.i_MOSTIMPSUBOP) AS t_CATEGORY,"
            "(SELECT s.t_REFUND FROM v_suboperation_display s WHERE s.id=v_operation.i_MOSTIMPSUBOP) AS t_REFUND,"
            "(CASE WHEN v_operation.f_QUANTITY<0 THEN '-' WHEN v_operation.f_QUANTITY=0 THEN '' ELSE '+' END) AS t_TYPEEXPENSE, "
            "(CASE WHEN v_operation.f_QUANTITY<=0 THEN '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a negative amount", "Expenditure")) % "' ELSE '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a positive amount", "Income")) % "' END) AS t_TYPEEXPENSENLS, "
            "STRFTIME('%Y-W%W',v_operation.d_date) AS d_DATEWEEK,"
            "STRFTIME('%Y-%m',v_operation.d_date) AS d_DATEMONTH,"
            "STRFTIME('%Y',v_operation.d_date)||'-Q'||(CASE WHEN STRFTIME('%m',v_operation.d_date)<='03' THEN '1' WHEN STRFTIME('%m',v_operation.d_date)<='06' THEN '2' WHEN STRFTIME('%m',v_operation.d_date)<='09' THEN '3' ELSE '4' END) AS d_DATEQUARTER, "
            "STRFTIME('%Y',v_operation.d_date)||'-S'||(CASE WHEN STRFTIME('%m',v_operation.d_date)<='06' THEN '1' ELSE '2' END) AS d_DATESEMESTER, "
            "STRFTIME('%Y',v_operation.d_date) AS d_DATEYEAR, "
            "(SELECT COUNT(1) FROM v_recurrentoperation s WHERE s.rd_operation_id=v_operation.id) AS i_NBRECURRENT,  "
            "(CASE WHEN v_operation.f_QUANTITY>=0 THEN v_operation.f_QUANTITY ELSE 0 END) AS f_QUANTITY_INCOME, "
            "(CASE WHEN v_operation.f_QUANTITY<=0 THEN v_operation.f_QUANTITY ELSE 0 END) AS f_QUANTITY_EXPENSE, "
            "(SELECT o2.f_balance FROM operationbalance o2 WHERE o2.r_operation_id=v_operation.id ) AS f_BALANCE, "
            "(SELECT o2.f_balance_entered FROM operationbalance o2 WHERE o2.r_operation_id=v_operation.id ) AS f_BALANCE_ENTERED, "
            "(CASE WHEN v_operation.f_QUANTITY>=0 THEN v_operation.f_CURRENTAMOUNT ELSE 0 END) AS f_CURRENTAMOUNT_INCOME, "
            "(CASE WHEN v_operation.f_QUANTITY<=0 THEN v_operation.f_CURRENTAMOUNT ELSE 0 END) AS f_CURRENTAMOUNT_EXPENSE "
            "FROM v_operation"

            << "CREATE VIEW  v_operation_display AS "
            "SELECT * FROM v_operation_display_all WHERE d_date!='0000-00-00' AND t_template='N'"

            // unit
            << "CREATE VIEW  v_unit_display AS "
            "SELECT *,"
            "i_nbdecimal AS i_NBDEC,"
            "(SELECT TOTAL(o.f_QUANTITY) FROM v_operation_display_all o WHERE o.rc_unit_id=v_unit.id AND o.t_template='N') AS f_QUANTITYOWNED, "
            "(SELECT TOTAL(o.f_QUANTITY) FROM v_operation_display_all o WHERE o.rc_unit_id=v_unit.id AND o.t_template='N')*v_unit.f_CURRENTAMOUNT AS f_AMOUNTOWNED "
            "FROM v_unit"

            // account
            << "CREATE VIEW  v_account_display AS "
            "SELECT "
            "(CASE t_type "
            "WHEN 'C' THEN '" % SKGServices::stringToSqlString(i18nc("Adjective, a current account", "Current")) % "' "
            "WHEN 'D' THEN '" % SKGServices::stringToSqlString(i18nc("Noun",  "Credit card")) % "' "
            "WHEN 'A' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, the type of an account", "Assets")) % "' "
            "WHEN 'I' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a type of account WHERE you invest money", "Investment")) % "' "
            "WHEN 'W' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a type of account", "Wallet")) % "' "
            "WHEN 'L' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a type of account", "Loan")) % "' "
            "WHEN 'S' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a type of account", "Saving")) % "' "
            "WHEN 'P' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, a type of account", "Pension")) % "' "
            "WHEN 'O' THEN '" % SKGServices::stringToSqlString(i18nc("Noun, as in other type of item", "Other")) % "' END) AS t_TYPENLS,"
            "v_account_amount.*,"
            "(v_account_amount.f_CURRENTAMOUNT/(SELECT u.f_CURRENTAMOUNT FROM v_unit u, operation s WHERE u.id=s.rc_unit_id AND s.rd_account_id=v_account_amount.id AND s.d_date='0000-00-00')) AS f_QUANTITY, "
            "(SELECT (CASE WHEN u.t_symbol!='' THEN u.t_symbol ELSE u.t_name END) FROM unit u, operation s WHERE u.id=s.rc_unit_id AND s.rd_account_id=v_account_amount.id AND s.d_date='0000-00-00') AS t_UNIT, "
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_operation s WHERE s.rd_account_id=v_account_amount.id AND s.t_status!='N' AND s.t_template='N') AS f_CHECKED, "
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_operation s WHERE s.rd_account_id=v_account_amount.id AND s.t_status='N' AND s.t_template='N') AS f_COMING_SOON, "
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_operation s WHERE s.rd_account_id IN (SELECT id FROM account WHERE account.r_account_id=v_account_amount.id) AND s.t_status='N' AND s.t_template='N') AS f_COMING_SOON_FROM_LINKED_ACCOUNT, "
            "(SELECT TOTAL(s.f_CURRENTAMOUNT) FROM v_operation s WHERE s.rd_account_id=v_account_amount.id AND s.d_date<=(SELECT date('now')) AND s.t_template='N') AS f_TODAYAMOUNT, "
            "(SELECT COUNT(1) FROM v_operation_display s WHERE s.rd_account_id=v_account_amount.id) AS i_NBOPERATIONS, "
            "IFNULL((SELECT s.f_rate FROM interest s WHERE s.rd_account_id=v_account_amount.id AND s.d_date=v_account_amount.d_MAXDATE),0) AS f_RATE "
            "FROM v_account_amount"

            // operations
            << "CREATE VIEW  v_suboperation_consolidated AS "
            "SELECT "
            "(SELECT s.t_TYPENLS FROM v_account_display s WHERE s.id=op.rd_account_id) AS t_ACCOUNTTYPE,"
            "(SELECT s.t_BANK FROM v_account_display s WHERE s.id=op.rd_account_id) AS t_BANK,"
            "(SELECT u.t_TYPENLS FROM v_unit u WHERE u.id=op.rc_unit_id) AS t_UNITTYPE,"
            "sop.id AS id, "
            "sop.id AS i_SUBOPID, "
            "sop.r_refund_id AS r_refund_id, "
            "(CASE WHEN sop.t_comment='' THEN op.t_comment ELSE sop.t_comment END) AS t_REALCOMMENT, "
            "sop.t_CATEGORY AS t_REALCATEGORY, "
            "sop.t_REFUND AS t_REALREFUND, "
            "sop.r_category_id AS i_IDCATEGORY, "
            "(CASE WHEN sop.f_value<0 THEN '-' WHEN sop.f_value=0 THEN '' ELSE '+' END) AS t_TYPEEXPENSE, "
            "(CASE WHEN sop.f_value<=0 THEN '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a negative amount", "Expenditure")) % "' ELSE '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a positive amount", "Income")) % "' END) AS t_TYPEEXPENSENLS, "
            "sop.f_value AS f_REALQUANTITY, "
            "sop.f_VALUE_INCOME AS f_REALQUANTITY_INCOME, "
            "sop.f_VALUE_EXPENSE AS f_REALQUANTITY_EXPENSE, "
            "((SELECT u.f_CURRENTAMOUNT FROM v_unit u WHERE u.id=op.rc_unit_id)*sop.f_value) AS f_REALCURRENTAMOUNT, "
            "((SELECT u.f_CURRENTAMOUNT FROM v_unit u WHERE u.id=op.rc_unit_id)*sop.f_VALUE_INCOME) AS f_REALCURRENTAMOUNT_INCOME, "
            "((SELECT u.f_CURRENTAMOUNT FROM v_unit u WHERE u.id=op.rc_unit_id)*sop.f_VALUE_EXPENSE) AS f_REALCURRENTAMOUNT_EXPENSE, "
            "STRFTIME('%Y-W%W',sop.d_date) AS d_DATEWEEK,"
            "STRFTIME('%Y-%m',sop.d_date) AS d_DATEMONTH,"
            "STRFTIME('%Y',sop.d_date)||'-Q'||(CASE WHEN STRFTIME('%m',sop.d_date)<='03' THEN '1' WHEN STRFTIME('%m',sop.d_date)<='06' THEN '2' WHEN STRFTIME('%m',sop.d_date)<='09' THEN '3' ELSE '4' END) AS d_DATEQUARTER, "
            "STRFTIME('%Y',sop.d_date)||'-S'||(CASE WHEN STRFTIME('%m',sop.d_date)<='06' THEN '1' ELSE '2' END) AS d_DATESEMESTER, "
            "STRFTIME('%Y',sop.d_date) AS d_DATEYEAR, "
            "sop.d_date AS d_date, "
            "op.id AS i_OPID, "
            "op.d_date AS d_DATEOP, "
            "op.* "
            "FROM v_operation_display_all AS op, v_suboperation_display AS sop WHERE +sop.rd_operation_id=op.ID AND op.t_template='N'"

            << "CREATE VIEW  v_operation_prop AS "
            "SELECT "
            "p.id AS i_PROPPID, "
            "p.t_name AS i_PROPPNAME, "
            "p.t_value AS i_PROPVALUE, "
            "op.* "
            "FROM v_suboperation_consolidated AS op LEFT OUTER JOIN parameters AS p ON (p.t_uuid_parent=op.id||'-suboperation' OR p.t_uuid_parent=op.i_OPID||'-operation')"

            // refund
            << "CREATE VIEW  v_refund_delete AS "
            "SELECT *, (CASE WHEN EXISTS(SELECT 1 FROM v_suboperation_consolidated WHERE r_refund_id=refund.id AND t_status='Y') THEN '" %
            SKGServices::stringToSqlString(i18nc("Error message",  "You are not authorized to delete this tracker because used by some checked operations")) %
            "' END) t_delete_message FROM refund"

            << "CREATE VIEW  v_refund AS SELECT * FROM refund"

            << "CREATE VIEW  v_refund_amount AS "
            "SELECT *, "
            "(SELECT TOTAL(o.f_REALCURRENTAMOUNT) FROM v_suboperation_consolidated o WHERE o.r_refund_id=v_refund.id) AS f_CURRENTAMOUNT "
            "FROM v_refund"

            << "CREATE VIEW  v_refund_display AS "
            "SELECT *,"
            "(SELECT MIN(o.d_date) FROM v_suboperation_consolidated o WHERE o.r_refund_id=v_refund_amount.id) AS d_FIRSTDATE, "
            "(SELECT MAX(o.d_date) FROM v_suboperation_consolidated o WHERE o.r_refund_id=v_refund_amount.id) AS d_LASTDATE "
            " FROM v_refund_amount"

            << "CREATE VIEW  v_refund_displayname AS "
            "SELECT *, t_name AS t_displayname FROM refund"

            // Payee
            << "CREATE VIEW  v_payee_delete AS "
            "SELECT *, (CASE WHEN EXISTS(SELECT 1 FROM operation WHERE r_payee_id=payee.id AND t_status='Y') THEN '" %
            SKGServices::stringToSqlString(i18nc("Error message",  "You are not authorized to delete this payee because used by some checked operations")) %
            "' END) t_delete_message FROM payee"

            << "CREATE VIEW v_payee_amount AS SELECT o.r_payee_id AS r_payee_id, TOTAL(o.f_CURRENTAMOUNT) AS f_CURRENTAMOUNT, COUNT(1) AS i_NBOPERATIONS FROM v_operation o GROUP BY o.r_payee_id"

            << "CREATE VIEW  v_payee AS SELECT * FROM payee"

            << "CREATE VIEW  v_payee_display AS "
            "SELECT payee.*, "
            "(CASE WHEN p.f_CURRENTAMOUNT IS NULL THEN 0 ELSE p.f_CURRENTAMOUNT END) AS f_CURRENTAMOUNT, "
            "(CASE WHEN p.i_NBOPERATIONS IS NULL THEN 0 ELSE p.i_NBOPERATIONS END) AS i_NBOPERATIONS "
            "FROM payee LEFT OUTER JOIN v_payee_amount p ON p.r_payee_id=payee.id"

            << "CREATE VIEW  v_payee_displayname AS "
            "SELECT *, t_name AS t_displayname FROM payee"

            // category
            << "CREATE VIEW  v_category_delete AS "
            "SELECT *, (CASE WHEN EXISTS(SELECT 1 FROM v_suboperation_consolidated WHERE (t_REALCATEGORY=category.t_fullname OR t_REALCATEGORY like category.t_fullname||'%') AND t_status='Y') THEN '" %
            SKGServices::stringToSqlString(i18nc("Error message",  "You are not authorized to delete this category because used by some checked operations")) %
            "' END) t_delete_message FROM category"

            << "CREATE VIEW  v_category_amount AS SELECT o.i_IDCATEGORY AS i_IDCATEGORY, TOTAL(o.f_REALCURRENTAMOUNT) AS f_REALCURRENTAMOUNT FROM v_suboperation_consolidated o GROUP BY o.i_IDCATEGORY"

            << "CREATE VIEW  v_category_display_tmp AS SELECT v_category.*, "
            "IFNULL(t.f_REALCURRENTAMOUNT, 0) AS f_REALCURRENTAMOUNT, "
            "(SELECT COUNT(DISTINCT(so.rd_operation_id)) FROM operation o, suboperation so WHERE +so.rd_operation_id=o.id AND so.r_category_id=v_category.ID AND o.t_template='N') AS i_NBOPERATIONS "
            "FROM v_category LEFT OUTER JOIN v_category_amount t ON t.i_IDCATEGORY=v_category.ID"

            << "CREATE VIEW  v_category_used1 AS SELECT v_category.*, "
            "(CASE WHEN EXISTS(SELECT 1 FROM operation o, suboperation so WHERE +so.rd_operation_id=o.id AND so.r_category_id=v_category.ID AND o.t_template='N') THEN 'Y' ELSE 'N' END) AS t_ISUSED "
            "FROM v_category"

            << "CREATE VIEW  v_category_used2 AS SELECT v_category_used1.*, "
            "(CASE WHEN v_category_used1.t_ISUSED='Y' THEN 'Y' WHEN EXISTS(SELECT 1 FROM v_category_used1 c WHERE c.t_ISUSED='Y' AND c.t_fullname like v_category_used1.t_fullname||'" % OBJECTSEPARATOR % "%') THEN 'C' ELSE 'N' END) AS t_ISUSEDCASCADE "
            "FROM v_category_used1"

            << "CREATE VIEW  v_category_display AS SELECT *,"
            "v_category_display_tmp.f_REALCURRENTAMOUNT+(SELECT TOTAL(c.f_REALCURRENTAMOUNT) FROM v_category_display_tmp c WHERE c.t_fullname LIKE v_category_display_tmp.t_fullname||'" % OBJECTSEPARATOR % "%') AS f_SUMCURRENTAMOUNT, "
            "v_category_display_tmp.i_NBOPERATIONS+(SELECT CAST(TOTAL(c.i_NBOPERATIONS) AS INTEGER) FROM v_category_display_tmp c WHERE c.t_fullname like v_category_display_tmp.t_fullname||'" % OBJECTSEPARATOR % "%') AS i_SUMNBOPERATIONS, "
            "(CASE WHEN v_category_display_tmp.t_bookmarked='Y' THEN 'Y' WHEN EXISTS(SELECT 1 FROM category c WHERE c.t_bookmarked='Y' AND c.t_fullname like v_category_display_tmp.t_fullname||'" % OBJECTSEPARATOR % "%') THEN 'C' ELSE 'N' END) AS t_HASBOOKMARKEDCHILD, "
            "(CASE WHEN v_category_display_tmp.f_REALCURRENTAMOUNT<0 THEN '-' WHEN v_category_display_tmp.f_REALCURRENTAMOUNT=0 THEN '' ELSE '+' END) AS t_TYPEEXPENSE,"
            "(CASE WHEN v_category_display_tmp.f_REALCURRENTAMOUNT<0 THEN '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a negative amount", "Expenditure")) % "' WHEN v_category_display_tmp.f_REALCURRENTAMOUNT=0 THEN '' ELSE '" % SKGServices::stringToSqlString(i18nc("Noun, financial operations with a positive amount", "Income")) % "' END) AS t_TYPEEXPENSENLS "
            "FROM v_category_display_tmp"

            // recurrentoperation
            << "CREATE VIEW  v_recurrentoperation_display AS "
            "SELECT rop.*, op.t_ACCOUNT, op.i_number, op.t_mode, op.i_group_id, op.t_TRANSFER, op.t_PAYEE, op.t_comment, op.t_CATEGORY, op.t_status, op.f_CURRENTAMOUNT "
            "FROM v_recurrentoperation rop, v_operation_display_all AS op WHERE +rop.rd_operation_id=op.ID"

            // rule
            << "CREATE VIEW v_rule AS SELECT *,"
            "(SELECT COUNT(1) FROM rule r WHERE r.f_sortorder<=rule.f_sortorder) AS i_ORDER "
            "FROM rule"
            << "CREATE VIEW v_rule_displayname AS SELECT *, t_description AS t_displayname FROM rule"

            << "CREATE VIEW v_rule_display AS SELECT * FROM v_rule"

            // interest
            << "CREATE VIEW v_interest AS SELECT *,"
            "(SELECT s.t_name FROM account s WHERE s.id=interest.rd_account_id) AS t_ACCOUNT "
            " FROM interest"
            << "CREATE VIEW v_interest_displayname AS SELECT *, IFNULL(STRFTIME('" % dateFormatShort % "',d_date),STRFTIME('%Y-%m-%d',d_date))||' '||f_rate||'%' AS t_displayname FROM interest"

            // budgetrule
            << "CREATE VIEW  v_budgetrule AS "
            "SELECT *, "
            "IFNULL((SELECT s.t_fullname FROM category s WHERE s.id=budgetrule.rc_category_id),'') AS t_CATEGORYCONDITION, "
            "IFNULL((SELECT s.t_fullname FROM category s WHERE s.id=budgetrule.rc_category_id_target),'') AS t_CATEGORY, "
            "(CASE "
            "WHEN budgetrule.i_condition=-1 THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Negative")) % "' "
            "WHEN budgetrule.i_condition=1 THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Positive")) % "' "
            "WHEN budgetrule.i_condition=0 THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "All")) % "' "
            "END) AS t_WHENNLS, "
            "f_quantity||(CASE WHEN budgetrule.t_absolute='N' THEN '%' ELSE (SELECT t_symbol FROM unit WHERE t_type='1') END) AS t_WHATNLS,"
            "(CASE "
            "WHEN budgetrule.t_rule='N' THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Next")) % "' "
            "WHEN budgetrule.t_rule='C' THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Current")) % "' "
            "WHEN budgetrule.t_rule='Y' THEN '" % SKGServices::stringToSqlString(i18nc("Noun", "Year")) % "' "
            "END) AS t_RULENLS "
            "FROM budgetrule"

            << "CREATE VIEW  v_budgetrule_display AS "
            "SELECT * "
            " FROM v_budgetrule"

            << "CREATE VIEW  v_budgetrule_displayname AS "
            "SELECT *, t_WHENNLS||' '||t_WHATNLS||' '||t_RULENLS||' '||t_CATEGORY AS t_displayname FROM v_budgetrule"

            // budget
            << "CREATE VIEW  v_budget_tmp AS "
            "SELECT *, "
            "IFNULL((SELECT s.t_fullname FROM category s WHERE s.id=budget.rc_category_id),'') AS t_CATEGORY, "
            "(budget.i_year||(CASE WHEN budget.i_month=0 THEN '' WHEN budget.i_month<10 THEN '-0'||budget.i_month ELSE '-'||budget.i_month END)) AS t_PERIOD, "
            "(SELECT TOTAL(o.f_REALCURRENTAMOUNT) FROM v_suboperation_consolidated o WHERE o.t_TYPEACCOUNT<>'L' AND o.i_SUBOPID IN "
            "(SELECT b2.id_suboperation FROM budgetsuboperation b2 WHERE b2.id=budget.id)"
            ") AS f_CURRENTAMOUNT, "
            "(SELECT GROUP_CONCAT(v_budgetrule_displayname.t_displayname,',') FROM v_budgetrule_displayname WHERE "
            "(v_budgetrule_displayname.t_year_condition='N' OR budget.i_year=v_budgetrule_displayname.i_year) AND "
            "(v_budgetrule_displayname.t_month_condition='N' OR budget.i_month=v_budgetrule_displayname.i_month) AND "
            "(v_budgetrule_displayname.t_category_condition='N' OR budget.rc_category_id=v_budgetrule_displayname.rc_category_id) "
            "ORDER BY v_budgetrule_displayname.t_absolute DESC, v_budgetrule_displayname.id) AS t_RULES "
            "FROM budget"

            << "CREATE VIEW  v_budget AS "
            "SELECT *, "
            "(f_CURRENTAMOUNT-f_budgeted_modified) AS f_DELTABEFORETRANSFER, "
            "(f_CURRENTAMOUNT-f_budgeted_modified-f_transferred) AS f_DELTA "
            "FROM v_budget_tmp"

            << "CREATE VIEW  v_budget_display AS "
            "SELECT *, "
            "(f_CURRENTAMOUNT-f_budgeted_modified) AS f_DELTABEFORETRANSFER, "
            "(f_CURRENTAMOUNT-f_budgeted_modified-f_transferred) AS f_DELTA "
            "FROM vm_budget_tmp"

            << "CREATE VIEW  v_budget_displayname AS "
            "SELECT *, t_CATEGORY||' '||t_PERIOD||' '||f_budgeted_modified AS t_displayname FROM v_budget"

            << "CREATE VIEW  v_operation_all_comment AS "
            "SELECT t_comment FROM operation UNION SELECT t_comment FROM suboperation";

    IFOKDO(err, SKGDocument::refreshViewsIndexesAndTriggers(iForce))
    QStringList tables;
    tables << "account" << "unit" << "unitvalue" << "bank" << "recurrentoperation" << "refund" << "payee" << "operation"
           << "operationbalance" << "interest" << "rule" << "suboperation" << "budget" << "budgetrule" << "budgetcategory" << "budgetsuboperation" << "category";
    IFOKDO(err, dropViewsAndIndexes(tables))
    IFOKDO(err, executeSqliteOrders(BankInitialDataModelIndex))
    IFOKDO(err, executeSqliteOrders(BankInitialDataModelView))
    IFOKDO(err, executeSqliteOrders(BankInitialDataModelTrigger))
    IFOKDO(err, executeSqliteOrder("ANALYZE"))

    return err;
}

SKGError SKGDocumentBank::migrate(bool& oMigrationDone)
{
    SKGError err;
    SKGTRACEINFUNCRC(5, err);
    oMigrationDone = false;
    QStringList migrationSteps;
    {
        migrationSteps
        // ============
                << ""
                << "0.1"
                << "0.2"
                << "ALTER TABLE unit ADD COLUMN rc_unit_id INTEGER NOT NULL DEFAULT 0"
                // ============
                << ""
                << "0.2"
                << "0.3"
                << "DROP TABLE IF EXISTS unitvalue2"
                << "CREATE TABLE unitvalue2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "rd_unit_id INTEGER NOT NULL,"
                "d_date DATE NOT NULL,"
                "f_quantity FLOAT NOT NULL CHECK (f_quantity>=0))"

                << "INSERT INTO unitvalue2 (id,rd_unit_id,d_date,f_quantity) SELECT id,rd_unit_id,d_date,f_value FROM unitvalue"

                << "DROP TABLE IF EXISTS unitvalue"
                << "ALTER TABLE unitvalue2 RENAME TO unitvalue"
                // ============
                << ""
                << "0.3"
                << "0.4"
                << "ALTER TABLE operation ADD COLUMN t_import_id TEXT DEFAULT ''"
                // ============
                << ""
                << "0.4"
                << "0.5"
                << "DROP TABLE IF EXISTS recurrentoperation"
                << "CREATE TABLE recurrentoperation ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_operation_id INTEGER NOT NULL,"
                "i_period_increment INTEGER NOT NULL DEFAULT 1 CHECK (i_period_increment>=0),"
                "t_period_unit TEXT NOT NULL DEFAULT 'M' CHECK (t_period_unit IN ('D', 'M', 'Y')),"
                "t_auto_write VARCHAR(1) DEFAULT 'Y' CHECK (t_auto_write IN ('Y', 'N')),"
                "i_auto_write_days INTEGER NOT NULL DEFAULT 5 CHECK (i_auto_write_days>=0),"
                "t_warn VARCHAR(1) DEFAULT 'Y' CHECK (t_auto_write IN ('Y', 'N')),"
                "i_warn_days INTEGER NOT NULL DEFAULT 5 CHECK (i_warn_days>=0)"
                ")"
                << "ALTER TABLE operation ADD COLUMN r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0"
                // ============
                << ""
                << "0.5"
                << "0.6"
                << "ALTER TABLE account ADD COLUMN t_comment TEXT NOT NULL DEFAULT ''"
                // ============
                << ""
                << "0.6"
                << "0.7"
                << "DROP TABLE IF EXISTS unit2"
                << "CREATE TABLE unit2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_symbol TEXT NOT NULL DEFAULT '',"
                "t_country TEXT NOT NULL DEFAULT '',"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('1', '2', 'C', 'S', 'O')),"
                // 1=main currency, 2=secondary currency, C=currencies S=share O=object
                "t_internet_code TEXT NOT NULL DEFAULT '',"
                "rd_unit_id INTEGER NOT NULL DEFAULT 0)"

                << "INSERT INTO unit2 (id,t_name,t_symbol,t_country,t_type,t_internet_code,rd_unit_id) SELECT id,t_name,t_symbol,t_country,t_type,t_internet_code,rc_unit_id FROM unit"

                << "DROP TABLE IF EXISTS unit"
                << "ALTER TABLE unit2 RENAME TO unit"
                // ============
                << ""
                << "0.7"
                << "0.8"
                << "DELETE FROM operation WHERE id IN (SELECT id FROM operation op WHERE NOT EXISTS(SELECT 1 FROM suboperation sop WHERE sop.rd_operation_id=op.id))"
                // ============
                << ""
                << "0.8"
                << "0.9"
                << "UPDATE operation SET i_group_id=0 WHERE i_group_id=''"
                // ============
                << ""
                << "0.9"
                << "1.0"
                << "DROP TABLE IF EXISTS unit2"
                << "CREATE TABLE unit2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_symbol TEXT NOT NULL DEFAULT '',"
                "t_country TEXT NOT NULL DEFAULT '',"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('1', '2', 'C', 'S', 'I', 'O')),"
                // 1=main currency, 2=secondary currency, C=currencies S=share, I=index, O=object
                "t_internet_code TEXT NOT NULL DEFAULT '',"
                "rd_unit_id INTEGER NOT NULL DEFAULT 0)"

                << "INSERT INTO unit2 (id,t_name,t_symbol,t_country,t_type,t_internet_code,rd_unit_id) SELECT id,t_name,t_symbol,t_country,t_type,t_internet_code,rd_unit_id FROM unit"

                << "DROP TABLE IF EXISTS unit"
                << "ALTER TABLE unit2 RENAME TO unit"
                // ============
                << ""
                << "1.0"
                << "1.1"
                << "DELETE FROM parameters WHERE t_name LIKE 'SKG_MONTHLY_REPORT_%'"
                // ============
                << ""
                << "1.1"
                << "1.2"
                << "ALTER TABLE suboperation ADD COLUMN t_comment TEXT NOT NULL DEFAULT ''"
                // ============
                << ""
                << "1.2"
                << "1.3"
                << "UPDATE node SET f_sortorder=id WHERE f_sortorder IS NULL OR f_sortorder=''"
                // ============
                << ""
                << "1.3"
                << "1.4"
                << "DROP TABLE IF EXISTS refund"
                << "CREATE TABLE refund ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')))"

                << "ALTER TABLE suboperation ADD COLUMN r_refund_id INTEGER NOT NULL DEFAULT 0"
                // ============
                << ""
                << "1.4"
                << "1.5"
                << "DELETE FROM parameters WHERE (t_name LIKE 'SKG_DEFAULT_%' AND t_name!='SKG_DEFAULT_PROPERTIES') OR t_name='DBVERSION'"
                // ============
                << ""
                << "1.5"
                << "1.6"
                << "CREATE TABLE rule ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_description TEXT NOT NULL DEFAULT '',"
                "t_definition TEXT NOT NULL DEFAULT '',"
                "f_sortorder FLOAT"
                ")"
                // ============
                << ""
                << "1.6"
                << "1.7"
                << "CREATE TABLE action ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "rd_rule_id INTEGER NOT NULL,"
                "t_description TEXT NOT NULL DEFAULT '',"
                "t_definition TEXT NOT NULL DEFAULT ''"
                ")"
                << "DELETE FROM rule"
                << "DROP TABLE IF EXISTS budget"
                // ============
                << ""
                << "1.7"
                << "1.8"
                << "DROP TABLE IF EXISTS action"
                << "ALTER TABLE rule ADD COLUMN t_action_description TEXT NOT NULL DEFAULT ''"
                << "ALTER TABLE rule ADD COLUMN t_action_definition TEXT NOT NULL DEFAULT ''"
                << "DROP TRIGGER IF EXISTS fkdc_rule_action_id_rd_rule_id"
                // ============
                << ""
                << "1.8"
                << "1.9"
                << "DROP TABLE IF EXISTS operation2"
                << "CREATE TABLE operation2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "i_group_id INTEGER NOT NULL DEFAULT 0,"
                "i_number INTEGER DEFAULT 0 CHECK (i_number>=0),"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_account_id INTEGER NOT NULL,"
                "t_mode TEXT NOT NULL DEFAULT '',"
                "t_payee TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "rc_unit_id INTEGER NOT NULL,"
                "t_status VARCHAR(1) DEFAULT 'N' CHECK (t_status IN ('N', 'P', 'Y')),"
                "t_bookmarked VARCHAR(1) DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "t_imported VARCHAR(1) DEFAULT 'N' CHECK (t_imported IN ('Y', 'N', 'P')),"
                "t_import_id TEXT DEFAULT '',"
                "r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0)"

                << "INSERT INTO operation2 (id,i_group_id,i_number,d_date,rd_account_id,t_mode,t_payee,t_comment,rc_unit_id,"
                "t_status,t_bookmarked,t_imported,t_import_id,r_recurrentoperation_id) "
                "SELECT id,i_group_id,i_number,d_date,rd_account_id,t_mode,t_payee,t_comment,rc_unit_id,"
                "(CASE WHEN t_status='C' THEN 'Y' ELSE t_status END),t_bookmarked,t_imported,t_import_id,r_recurrentoperation_id FROM operation"

                << "DROP TABLE IF EXISTS operation"
                << "ALTER TABLE operation2 RENAME TO operation"
                // ============
                << ""
                << "1.9"
                << "2.0"
                << "ALTER TABLE operation ADD COLUMN i_tmp INTEGER NOT NULL DEFAULT 0"
                << "ALTER TABLE suboperation ADD COLUMN i_tmp INTEGER NOT NULL DEFAULT 0"
                // ============
                << ""
                << "2.0"
                << "2.1"
                << "ALTER TABLE operation ADD COLUMN t_template VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_template IN ('Y', 'N'))"
                // ============
                << ""
                << "2.1"
                << "2.2"
                << "UPDATE recurrentoperation SET d_date=date(d_date,i_period_increment||(CASE WHEN t_period_unit='Y' THEN ' year' ELSE (CASE WHEN t_period_unit='M' THEN ' month' ELSE ' day' END) END))"


                << "DROP TABLE IF EXISTS recurrentoperation2"
                << "CREATE TABLE recurrentoperation2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_operation_id INTEGER NOT NULL,"
                "i_period_increment INTEGER NOT NULL DEFAULT 1 CHECK (i_period_increment>=0),"
                "t_period_unit TEXT NOT NULL DEFAULT 'M' CHECK (t_period_unit IN ('D', 'M', 'Y')),"
                "t_auto_write VARCHAR(1) DEFAULT 'Y' CHECK (t_auto_write IN ('Y', 'N')),"
                "i_auto_write_days INTEGER NOT NULL DEFAULT 5 CHECK (i_auto_write_days>=0),"
                "t_warn VARCHAR(1) DEFAULT 'Y' CHECK (t_warn IN ('Y', 'N')),"
                "i_warn_days INTEGER NOT NULL DEFAULT 5 CHECK (i_warn_days>=0),"
                "t_times VARCHAR(1) DEFAULT 'N' CHECK (t_times IN ('Y', 'N')),"
                "i_nb_times INTEGER NOT NULL DEFAULT 1 CHECK (i_nb_times>=0)"
                ")"

                << "INSERT INTO recurrentoperation2 (id,d_date,rd_operation_id,i_period_increment,t_period_unit,t_auto_write,i_auto_write_days,t_warn,i_warn_days) "
                "SELECT id,d_date,rd_operation_id,i_period_increment,t_period_unit,t_auto_write,i_auto_write_days,t_warn,i_warn_days FROM recurrentoperation"

                << "DROP TABLE IF EXISTS recurrentoperation"
                << "ALTER TABLE recurrentoperation2 RENAME TO recurrentoperation"
                // ============
                << ""
                << "2.2"
                << "2.3"
                << "UPDATE rule SET t_definition=replace(t_definition,'%9','#ATT#')"
                << "UPDATE rule SET t_definition=replace(t_definition,'''%1''','''#V1S#''')"
                << "UPDATE rule SET t_definition=replace(t_definition,'''%2''','''#V2S#''')"
                << "UPDATE rule SET t_definition=replace(t_definition,'''%%1%''','''%#V1S#%''')"
                << "UPDATE rule SET t_definition=replace(t_definition,'''%1%''','''#V1S#%''')"
                << "UPDATE rule SET t_definition=replace(t_definition,'''%%1''','''%#V1S#''')"
                << "UPDATE rule SET t_definition=replace(t_definition,'%1','#V1#')"
                << "UPDATE rule SET t_definition=replace(t_definition,'%2','#V2#')"

                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'%9','#ATT#')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'''%1''','''#V1S#''')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'''%2''','''#V2S#''')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'''%%1%''','''%#V1S#%''')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'''%1%''','''#V1S#%''')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'''%%1''','''%#V1S#''')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'%1','#V1#')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'%2','#V2#')"
                // ============
                << ""
                << "2.3"
                << "2.4"
                << "UPDATE operation SET t_template='N' WHERE t_template NOT IN ('Y', 'N')"
                // ============
                << ""
                << "2.4"
                << "2.5"
                << "ALTER TABLE rule ADD COLUMN t_action_type VARCHAR(1) DEFAULT 'S' CHECK (t_action_type IN ('S', 'U', 'A'))"
                << "UPDATE rule SET t_action_type='S' WHERE t_action_type NOT IN ('S', 'U', 'A') AND  t_action_definition=''"
                << "UPDATE rule SET t_action_type='U' WHERE t_action_type NOT IN ('S', 'U', 'A') AND  t_action_definition!=''"
                // ============
                << ""
                << "2.5"
                << "2.6"
                << "ALTER TABLE unit ADD COLUMN i_nbdecimal INT NOT NULL DEFAULT 2"
                << "UPDATE unit SET i_nbdecimal=2"
                // ============
                << ""
                << "2.6"
                << "2.7"
                << "CREATE TABLE operation2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "i_group_id INTEGER NOT NULL DEFAULT 0,"
                "i_number INTEGER DEFAULT 0 CHECK (i_number>=0),"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_account_id INTEGER NOT NULL,"
                "t_mode TEXT NOT NULL DEFAULT '',"
                "t_payee TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "rc_unit_id INTEGER NOT NULL,"
                "t_status VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_status IN ('N', 'P', 'Y')),"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "t_imported VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_imported IN ('Y', 'N', 'P', 'T')),"
                "t_template VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_template IN ('Y', 'N')),"
                "t_import_id TEXT NOT NULL DEFAULT '',"
                "i_tmp INTEGER NOT NULL DEFAULT 0,"
                "r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0)"

                << "INSERT INTO operation2 ("
                "id,i_group_id,i_number,d_date,rd_account_id,t_mode,t_payee,t_comment,rc_unit_id,t_status,t_bookmarked,t_imported,t_template,t_import_id,i_tmp,r_recurrentoperation_id) "
                "SELECT id,i_group_id,i_number,d_date,rd_account_id,t_mode,t_payee,t_comment,rc_unit_id,t_status,t_bookmarked,t_imported,t_template,t_import_id,i_tmp,r_recurrentoperation_id FROM operation"

                << "DROP TABLE IF EXISTS operation"
                << "ALTER TABLE operation2 RENAME TO operation"
                // ============
                << ""
                << "2.7"
                << "2.8"
                << "UPDATE rule SET t_action_type='U' WHERE t_action_type='S' AND  t_action_definition!=''"
                // ============
                << ""
                << "2.8"
                << "2.9"
                << "DROP TABLE IF EXISTS interest"
                << "CREATE TABLE interest("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "rd_account_id INTEGER NOT NULL,"
                "d_date DATE NOT NULL,"
                "f_rate FLOAT NOT NULL CHECK (f_rate>=0),"
                "t_income_value_date_mode VARCHAR(1) NOT NULL DEFAULT 'F' CHECK (t_income_value_date_mode IN ('F', '0', '1', '2', '3', '4', '5')),"
                "t_expenditure_value_date_mode VARCHAR(1) NOT NULL DEFAULT 'F' CHECK (t_expenditure_value_date_mode IN ('F', '0', '1', '2', '3', '4', '5')),"
                "t_base VARCHAR(3) NOT NULL DEFAULT '24' CHECK (t_base IN ('24', '360', '365'))"
                ")"
                // ============
                << ""
                << "2.9"
                << "3.0"
                // Current month
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"1\"\"', 'period=\"\"1\"\" interval=\"\"2\"\" nb_intervals=\"\"1\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Previous month
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"2\"\"', 'period=\"\"2\"\" interval=\"\"2\"\" nb_intervals=\"\"1\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Current year
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"3\"\"', 'period=\"\"1\"\" interval=\"\"3\"\" nb_intervals=\"\"1\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Previous year
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"4\"\"', 'period=\"\"2\"\" interval=\"\"3\"\" nb_intervals=\"\"1\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 30 days
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"5\"\"', 'period=\"\"3\"\" interval=\"\"0\"\" nb_intervals=\"\"30\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 3 months
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"6\"\"', 'period=\"\"3\"\" interval=\"\"2\"\" nb_intervals=\"\"3\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 6 months
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"7\"\"', 'period=\"\"3\"\" interval=\"\"2\"\" nb_intervals=\"\"6\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 12 months
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"8\"\"', 'period=\"\"3\"\" interval=\"\"2\"\" nb_intervals=\"\"12\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 2 years
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"9\"\"', 'period=\"\"3\"\" interval=\"\"3\"\" nb_intervals=\"\"2\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 3 years
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"10\"\"', 'period=\"\"3\"\" interval=\"\"3\"\" nb_intervals=\"\"3\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Last 5 years
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"11\"\"', 'period=\"\"3\"\" interval=\"\"3\"\" nb_intervals=\"\"5\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Custom...
                << "UPDATE node SET t_data=replace(t_data, 'period=\"\"12\"\"', 'period=\"\"4\"\"') WHERE t_data like '%Skrooge report plugin%'"

                // All without transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"0\"\"', 'incomes=\"\"Y\"\" expenses=\"\"Y\"\" transfers=\"\"N\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Income without transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"1\"\"', 'incomes=\"\"Y\"\" expenses=\"\"N\"\" transfers=\"\"N\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Expenditure without transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"2\"\"', 'incomes=\"\"N\"\" expenses=\"\"Y\"\" transfers=\"\"N\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // All with transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"3\"\"', 'incomes=\"\"Y\"\" expenses=\"\"Y\"\" transfers=\"\"Y\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Income with transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"4\"\"', 'incomes=\"\"Y\"\" expenses=\"\"N\"\" transfers=\"\"Y\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // Expenditure with transfers
                << "UPDATE node SET t_data=replace(t_data, 'type=\"\"5\"\"', 'incomes=\"\"N\"\" expenses=\"\"Y\"\" transfers=\"\"Y\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // ============
                << ""
                << "3.0"
                << "3.1"
                << "UPDATE node SET t_data=replace(t_data, 'columns=\"\"2\"\"', 'columns=\"\"4\"\"') WHERE t_data like '%Skrooge report plugin%'"
                << "UPDATE node SET t_data=replace(t_data, 'columns=\"\"1\"\"', 'columns=\"\"3\"\"') WHERE t_data like '%Skrooge report plugin%'"
                // ============
                << ""
                << "3.1"
                << "3.2"
                << "UPDATE parameters SET t_name='SKGSEARCH_DEFAULT_PARAMETERS' WHERE t_name='SKGIMPORT_DEFAULT_PARAMETERS'"
                // ============
                << ""
                << "3.2"
                << "3.3"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;4&quot;', ' columns=&quot;&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;3&quot;', ' columns=&quot;d_DATEYEAR&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;2&quot;', ' columns=&quot;d_DATESEMESTER&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;1&quot;', ' columns=&quot;d_DATEQUARTER&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;0&quot;', ' columns=&quot;d_DATEMONTH&quot;') WHERE t_data like '%graphicViewState=%'"

                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"4\"\"', ' columns=\"\"\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"3\"\"', ' columns=\"\"d_DATEYEAR\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"2\"\"', ' columns=\"\"d_DATESEMESTER\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"1\"\"', ' columns=\"\"d_DATEQUARTER\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"0\"\"', ' columns=\"\"d_DATEMONTH\"\"') WHERE t_data like '%graphicViewState=%'"

                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&quot;4&quot;', ' columns=&quot;&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&quot;3&quot;', ' columns=&quot;d_DATEYEAR&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&quot;2&quot;', ' columns=&quot;d_DATESEMESTER&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&quot;1&quot;', ' columns=&quot;d_DATEQUARTER&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&quot;0&quot;', ' columns=&quot;d_DATEMONTH&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"


                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;0&quot;', ' lines=&quot;t_REALCATEGORY&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;1&quot;', ' lines=&quot;t_payee&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;2&quot;', ' lines=&quot;t_mode&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;3&quot;', ' lines=&quot;t_TYPEEXPENSENLS&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;4&quot;', ' lines=&quot;t_status&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;5&quot;', ' lines=&quot;t_ACCOUNTTYPE&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;6&quot;', ' lines=&quot;t_UNITTYPE&quot;') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;7&quot;', ' lines=&quot;t_REALREFUND&quot;') WHERE t_data like '%graphicViewState=%'"

                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"0\"\"', ' lines=\"\"t_REALCATEGORY\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"1\"\"', ' lines=\"\"t_payee\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"2\"\"', ' lines=\"\"t_mode\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"3\"\"', ' lines=\"\"t_TYPEEXPENSENLS\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"4\"\"', ' lines=\"\"t_status\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"5\"\"', ' lines=\"\"t_ACCOUNTTYPE\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"6\"\"', ' lines=\"\"t_UNITTYPE\"\"') WHERE t_data like '%graphicViewState=%'"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"7\"\"', ' lines=\"\"t_REALREFUND\"\"') WHERE t_data like '%graphicViewState=%'"

                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;0&quot;', ' lines=&quot;t_REALCATEGORY&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;1&quot;', ' lines=&quot;t_payee&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;2&quot;', ' lines=&quot;t_mode&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;3&quot;', ' lines=&quot;t_TYPEEXPENSENLS&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;4&quot;', ' lines=&quot;t_status&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;5&quot;', ' lines=&quot;t_ACCOUNTTYPE&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;6&quot;', ' lines=&quot;t_UNITTYPE&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&quot;7&quot;', ' lines=&quot;t_REALREFUND&quot;') WHERE t_name='SKGDASHBOARD_DEFAULT_PARAMETERS'"
                // ============
                << ""
                << "3.3"
                << "3.4"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=\"4\"', ' columns=\"\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=\"3\"', ' columns=\"d_DATEYEAR\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=\"2\"', ' columns=\"d_DATESEMESTER\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=\"1\"', ' columns=\"d_DATEQUARTER\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=\"0\"', ' columns=\"d_DATEMONTH\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"


                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"0\"', ' lines=\"t_REALCATEGORY\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"1\"', ' lines=\"t_payee\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"2\"', ' lines=\"t_mode\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"3\"', ' lines=\"t_TYPEEXPENSENLS\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"4\"', ' lines=\"t_status\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"5\"', ' lines=\"t_ACCOUNTTYPE\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"6\"', ' lines=\"t_UNITTYPE\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=\"7\"', ' lines=\"t_REALREFUND\"') WHERE t_name='SKGREPORT_DEFAULT_PARAMETERS'"
                // ============
                << ""
                << "3.4"
                << "3.5"
                << "ALTER TABLE account ADD COLUMN t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                << "UPDATE account SET t_bookmarked='N'"
                // ============
                << ""
                << "3.5"
                << "3.6"
                << "ALTER TABLE rule ADD COLUMN t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                << "UPDATE rule SET t_bookmarked='N'"
                // ============
                << ""
                << "3.6"
                << "3.7"
                << "UPDATE suboperation SET r_category_id=0 WHERE r_category_id=(SELECT id FROM category WHERE t_name='')"
                << "DELETE FROM category WHERE t_name=''"
                // ============
                << ""
                << "3.7"
                << "3.8"
                << "UPDATE recurrentoperation SET t_times='N' WHERE t_times IS NULL"
                // ============
                << ""
                << "3.8"
                << "3.9"
                << "UPDATE node SET t_data=replace(t_data, 'Skrooge dashboard plugin', 'Dashboard plugin') WHERE t_data like '%Skrooge dashboard plugin%'"
                // ============
                << ""
                << "3.9"
                << "4.0"
                << "UPDATE rule SET t_definition=replace(t_definition, '" % SKGServices::stringToSqlString("date('now','-1") % "', '" % SKGServices::stringToSqlString("date('now','start of month','-1") % "')"
                // ============
                << ""
                << "4.0"
                << "4.1"
                << "UPDATE rule SET t_definition=replace(t_definition,'t_REFUND','t_REALREFUND')"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition,'t_REFUND','t_REALREFUND')"
                // ============
                << ""
                << "4.1"
                << "4.2"
                << "UPDATE operation SET t_imported='Y' WHERE t_imported='T'"
                << "UPDATE operation SET t_imported='N' WHERE t_imported!='N' AND t_import_id='';"
                // ============
                << ""
                << "4.2"
                << "4.3"
                <<  "CREATE TABLE payee ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL DEFAULT '',"
                "t_address TEXT NOT NULL DEFAULT '')"

                << "INSERT INTO payee (t_name) "
                "SELECT distinct(operation.t_payee) FROM operation WHERE operation.t_payee<>''"

                << "CREATE TABLE operation2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "i_group_id INTEGER NOT NULL DEFAULT 0,"
                "i_number INTEGER DEFAULT 0 CHECK (i_number>=0),"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_account_id INTEGER NOT NULL,"
                "t_mode TEXT NOT NULL DEFAULT '',"
                "r_payee_id INTEGER NOT NULL DEFAULT 0,"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "rc_unit_id INTEGER NOT NULL,"
                "t_status VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_status IN ('N', 'P', 'Y')),"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "t_imported VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_imported IN ('Y', 'N', 'P', 'T')),"
                "t_template VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_template IN ('Y', 'N')),"
                "t_import_id TEXT NOT NULL DEFAULT '',"
                "i_tmp INTEGER NOT NULL DEFAULT 0,"
                "r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0)"

                << "INSERT INTO operation2 ("
                "id,i_group_id,i_number,d_date,rd_account_id,t_mode,r_payee_id,t_comment,rc_unit_id,t_status,t_bookmarked,t_imported,t_template,t_import_id,i_tmp,r_recurrentoperation_id) "
                "SELECT id,i_group_id,i_number,d_date,rd_account_id,t_mode,(CASE WHEN (SELECT payee.id FROM payee WHERE payee.t_name=operation.t_payee) IS NULL THEN 0 ELSE (SELECT payee.id FROM payee WHERE payee.t_name=operation.t_payee) END),t_comment,rc_unit_id,t_status,t_bookmarked,t_imported,t_template,t_import_id,i_tmp,r_recurrentoperation_id FROM operation"

                << "DROP TABLE IF EXISTS operation"
                << "ALTER TABLE operation2 RENAME TO operation"

                << "UPDATE parameters SET t_value=replace(t_value, 't_payee', 't_PAYEE') WHERE t_name like '%_DEFAULT_PARAMETERS'"
                // ============
                << ""
                << "4.3"
                << "4.4"
                << "UPDATE rule SET t_definition=replace(t_definition, 't_payee', 't_PAYEE') WHERE t_definition like '%t_payee'"
                << "UPDATE node SET t_data=replace(t_data, 't_payee', 't_PAYEE') WHERE t_data like '%t_payee'"
                // ============
                << ""
                << "4.4"
                << "4.5"
                << "UPDATE rule SET t_definition=replace(t_definition, 't_payee', 't_PAYEE') WHERE t_definition like '%t_payee%'"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition, 't_payee', 't_PAYEE') WHERE t_action_definition like '%t_payee%'"
                // ============
                << ""
                << "4.5"
                << "4.6"
                << "DELETE FROM suboperation WHERE NOT EXISTS (SELECT 1 FROM operation WHERE operation.id=suboperation.rd_operation_id)"
                // ============
                << ""
                << "4.6"
                << "4.7"
                << "UPDATE node SET t_data=replace(t_data, ' smoothScrolling=&quot;N&quot;', ' zoomPosition=&quot;0&quot;') WHERE t_data like '% smoothScrolling=&quot;N&quot;%'"
                << "UPDATE node SET t_data=replace(t_data, ' smoothScrolling=&quot;Y&quot;', ' zoomPosition=&quot;0&quot;') WHERE t_data like '% smoothScrolling=&quot;Y&quot;%'"
                << "UPDATE parameters SET t_value=replace(t_value, ' smoothScrolling=&quot;N&quot;', ' zoomPosition=&quot;0&quot;') WHERE t_value like '% smoothScrolling=&quot;N&quot;%'"
                << "UPDATE parameters SET t_value=replace(t_value, ' smoothScrolling=&quot;Y&quot;', ' zoomPosition=&quot;0&quot;') WHERE t_value like '% smoothScrolling=&quot;Y&quot;%'"
                // ============
                << ""
                << "4.7"
                << "4.8"
                << "CREATE TABLE operationbalance("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "f_balance FLOAT NOT NULL DEFAULT 0,"
                "r_operation_id INTEGER NOT NULL)"
                // ============
                << ""
                << "4.8"
                << "4.9"
                <<
                "UPDATE node SET t_data=replace(t_data, ' lines=&quot;t_ACCOUNTTYPE&quot; nbLevelLines=&quot;0&quot;', ' lines=&quot;&quot; nbLevelLines=&quot;0&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"t_ACCOUNTTYPE\"\" nbLevelLines=\"\"0\"\"', ' lines=\"\"\"\" nbLevelLines=\"\"0\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot; nbLevelLines=&amp;quot;0&amp;quot;', ' lines=&amp;quot;&amp;quot; nbLevelLines=&amp;quot;0&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot; nbLevelLines=&amp;quot;0&amp;quot;', ' lines=&amp;quot;&amp;quot; nbLevelLines=&amp;quot;0&amp;quot;')"

                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;t_UNITTYPE&quot;', ' lines=&quot;t_UNITTYPE&quot; lines2=&quot;t_UNIT&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"t_UNITTYPE\"\"', ' lines=\"\"t_UNITTYPE\"\"  lines2=\"\"t_UNIT\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&amp;quot;t_UNITTYPE&amp;quot;', ' lines=&amp;quot;t_UNITTYPE&amp;quot; lines2=&amp;quot;t_UNIT&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&amp;quot;t_UNITTYPE&amp;quot;', ' lines=&amp;quot;t_UNITTYPE&amp;quot; lines2=&amp;quot;t_UNIT&amp;quot;')"

                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;t_ACCOUNTTYPE&quot;', ' lines=&quot;t_ACCOUNTTYPE&quot; lines2=&quot;t_ACCOUNT&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"t_ACCOUNTTYPE\"\"', ' lines=\"\"t_ACCOUNTTYPE\"\"  lines2=\"\"t_ACCOUNT\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot;', ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot; lines2=&amp;quot;t_ACCOUNT&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot;', ' lines=&amp;quot;t_ACCOUNTTYPE&amp;quot; lines2=&amp;quot;t_ACCOUNT&amp;quot;')"

                // ============
                << ""
                << "4.9"
                << "5.0"
                << "CREATE TABLE budget ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "rc_category_id INTEGER NOT NULL DEFAULT 0,"
                "f_budgeted FLOAT NOT NULL DEFAULT 0.0,"
                "i_year INTEGER NOT NULL DEFAULT 2010,"
                "i_month INTEGER NOT NULL DEFAULT 0 CHECK (i_month>=0 AND i_month<=12)"
                ")"
                // ============
                << ""
                << "5.0"
                << "5.1"
                << "CREATE TABLE budgetrule ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "rc_category_id INTEGER NOT NULL DEFAULT 0,"
                "i_year INTEGER NOT NULL DEFAULT 2010,"
                "i_month INTEGER NOT NULL DEFAULT 0 CHECK (i_month>=0 AND i_month<=12),"
                "i_condition INTEGER NOT NULL DEFAULT 0 CHECK (i_condition IN (-1,0,1)),"
                "f_quantity FLOAT NOT NULL DEFAULT 0.0,"
                "t_absolute TEXT NOT NULL DEFAULT 'Y' CHECK (t_absolute IN ('Y', 'N')),"
                "rc_category_id_target INTEGER NOT NULL DEFAULT 0,"
                "t_rule TEXT NOT NULL DEFAULT 'N' CHECK (t_rule IN ('N', 'C', 'Y'))"
                ")"
                // ============
                << ""
                << "5.1"
                << "5.2"
                << "CREATE TABLE budgetcategory("
                "id INTEGER NOT NULL DEFAULT 0,"
                "id_category INTEGER NOT NULL DEFAULT 0)"
                // ============
                << ""
                << "5.2"
                << "5.3"
                << "ALTER TABLE budget ADD COLUMN f_budgeted_modified FLOAT NOT NULL DEFAULT 0.0"
                << "UPDATE budget SET f_budgeted_modified=f_budgeted"
                // ============
                << ""
                << "5.3"
                << "5.4"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&quot;&quot;', ' lines=&quot;#NOTHING#&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=\"\"\"\"', ' lines=\"\"#NOTHING#\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' lines=&amp;quot;&amp;quot;', ' lines=&amp;quot;#NOTHING#&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines=&amp;quot;&amp;quot;', ' lines=&amp;quot;#NOTHING#&amp;quot;')"

                << "UPDATE node SET t_data=replace(t_data, ' lines2=&quot;&quot;', ' lines2=&quot;#NOTHING#&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' lines2=\"\"\"\"', ' lines2=\"\"#NOTHING#\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' lines2=&amp;quot;&amp;quot;', ' lines2=&amp;quot;#NOTHING#&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' lines2=&amp;quot;&amp;quot;', ' lines2=&amp;quot;#NOTHING#&amp;quot;')"

                << "UPDATE node SET t_data=replace(t_data, ' columns=&quot;&quot;', ' columns=&quot;#NOTHING#&quot;')"
                << "UPDATE node SET t_data=replace(t_data, ' columns=\"\"\"\"', ' columns=\"\"#NOTHING#\"\"')"
                << "UPDATE node SET t_data=replace(t_data, ' columns=&amp;quot;&amp;quot;', ' columns=&amp;quot;#NOTHING#&amp;quot;')"
                << "UPDATE parameters SET t_value=replace(t_value, ' columns=&amp;quot;&amp;quot;', ' columns=&amp;quot;#NOTHING#&amp;quot;')"
                // ============
                << ""
                << "5.4"
                << "5.5"
                << "ALTER TABLE budgetrule ADD COLUMN t_category_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_category_condition IN ('Y', 'N'))"
                << "ALTER TABLE budgetrule ADD COLUMN t_year_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_year_condition IN ('Y', 'N'))"
                << "ALTER TABLE budgetrule ADD COLUMN t_month_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_month_condition IN ('Y', 'N'))"

                << "UPDATE budgetrule SET t_year_condition='Y'"
                << "UPDATE budgetrule SET t_year_condition='N', i_year=2010 WHERE i_year=0"
                << "UPDATE budgetrule SET t_month_condition='Y'"
                << "UPDATE budgetrule SET t_month_condition='N', i_month=1 WHERE i_month=0"
                << "UPDATE budgetrule SET t_category_condition='Y'"
                << "UPDATE budgetrule SET t_category_condition='N' WHERE rc_category_id=0"
                // ============
                << ""
                << "5.5"
                << "5.6"
                << "ALTER TABLE budgetrule ADD COLUMN t_category_target TEXT NOT NULL DEFAULT 'Y' CHECK (t_category_target IN ('Y', 'N'))"
                << "UPDATE budgetrule SET t_category_target='N'"
                // ============
                << ""
                << "5.6"
                << "5.7"
                << "ALTER TABLE budget ADD COLUMN f_transferred FLOAT NOT NULL DEFAULT 0.0"
                << "UPDATE budget SET f_transferred=0"
                // ============
                << ""
                << "5.7"
                << "5.8"
                << "ALTER TABLE budget ADD COLUMN t_including_subcategories TEXT NOT NULL DEFAULT 'N' CHECK (t_including_subcategories IN ('Y', 'N'));"
                << "UPDATE budget SET t_including_subcategories='N'"
                // ============
                << ""
                << "5.8"
                << "5.9"
                << "DELETE FROM parameters WHERE t_uuid_parent='advices';"
                // ============
                << ""
                << "5.9"
                << "6.0"
                << "UPDATE category SET t_name=t_name;"
                // ============
                << ""
                << "6.0"
                << "6.1"
                << "UPDATE node SET t_data=replace(t_data,'t_type', 't_TYPENLS')"
                << "UPDATE parameters SET t_value=replace(t_value, 't_type', 't_TYPENLS') where t_name like '%_DEFAULT_PARAMETERS'"
                // ============
                << ""
                << "6.1"
                << "6.2"
                << "CREATE TABLE account2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_number TEXT NOT NULL DEFAULT '',"
                "t_agency_number TEXT NOT NULL DEFAULT '',"
                "t_agency_address TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('C', 'D', 'A', 'I', 'O', 'W')),"
                // C=current D=credit card A=assets (for objects) I=Investment W=Wallet O=other
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "rd_bank_id INTEGER NOT NULL)"
                << "INSERT INTO account2 (id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id) "
                "SELECT id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id FROM account"
                << "DROP TABLE IF EXISTS account"
                << "ALTER TABLE account2 RENAME TO account"
                // ============
                << ""
                << "6.2"
                << "6.3"
                << "ALTER TABLE suboperation ADD COLUMN t_formula TEXT NOT NULL DEFAULT '';"
                << "UPDATE suboperation SET t_formula=''"
                // ============
                << ""
                << "6.3"
                << "6.4"
                << "CREATE TABLE vm_category_display_tmp(  id INT,  t_name TEXT,  t_fullname TEXT,  rd_category_id INT,  i_NBOPERATIONS,  f_REALCURRENTAMOUNT)"
                // ============
                << ""
                << "6.4"
                << "6.5"
                << "ALTER TABLE category ADD COLUMN t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'));"
                << "ALTER TABLE payee ADD COLUMN t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'));"
                << "UPDATE category SET t_bookmarked='N'"
                << "UPDATE payee SET t_bookmarked='N'"
                // ============
                << ""
                << "6.5"
                << "6.6"
                << "CREATE TABLE vm_budget_tmp(  id INT,  rc_category_id INT,  f_budgeted REAL,  i_year INT,  i_month INT,  f_budgeted_modified REAL,  f_transferred REAL,  t_including_subcategories TEXT,  t_CATEGORY,  t_PERIOD,  f_CURRENTAMOUNT,  t_RULES)"
                // ============
                << ""
                << "6.6"
                << "6.7"
                << "DROP TABLE IF EXISTS vm_category_display_tmp"
                << "CREATE TABLE vm_category_display_tmp(  id INT,  t_name TEXT,  t_fullname TEXT,  rd_category_id INT,  i_NBOPERATIONS,  f_REALCURRENTAMOUNT, t_bookmarked)"
                // ============
                << ""
                << "6.7"
                << "6.8"
                << "CREATE TABLE recurrentoperation2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "rd_operation_id INTEGER NOT NULL,"
                "i_period_increment INTEGER NOT NULL DEFAULT 1 CHECK (i_period_increment>=0),"
                "t_period_unit TEXT NOT NULL DEFAULT 'M' CHECK (t_period_unit IN ('D', 'W', 'M', 'Y')),"
                "t_auto_write VARCHAR(1) DEFAULT 'Y' CHECK (t_auto_write IN ('Y', 'N')),"
                "i_auto_write_days INTEGER NOT NULL DEFAULT 5 CHECK (i_auto_write_days>=0),"
                "t_warn VARCHAR(1) DEFAULT 'Y' CHECK (t_warn IN ('Y', 'N')),"
                "i_warn_days INTEGER NOT NULL DEFAULT 5 CHECK (i_warn_days>=0),"
                "t_times VARCHAR(1) DEFAULT 'N' CHECK (t_times IN ('Y', 'N')),"
                "i_nb_times INTEGER NOT NULL DEFAULT 1 CHECK (i_nb_times>=0)"
                ")"

                << "INSERT INTO recurrentoperation2 (id,d_date,rd_operation_id,i_period_increment,t_period_unit,t_auto_write,i_auto_write_days,t_warn,i_warn_days,t_times,i_nb_times) "
                "SELECT id,d_date,rd_operation_id,i_period_increment,t_period_unit,t_auto_write,i_auto_write_days,t_warn,i_warn_days,t_times,i_nb_times FROM recurrentoperation"

                << "DROP TABLE IF EXISTS recurrentoperation"
                << "ALTER TABLE recurrentoperation2 RENAME TO recurrentoperation"
                // ============
                << ""
                << "6.8"
                << "6.9"
                << "CREATE TABLE category2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL DEFAULT '' CHECK (t_name NOT LIKE '%" % OBJECTSEPARATOR % "%'),"
                "t_fullname TEXT,"
                "rd_category_id INT,"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                ")"
                << "INSERT INTO category2 (id, t_name, t_fullname, rd_category_id, t_bookmarked) "
                "SELECT id, t_name, t_fullname, r_category_id, t_bookmarked FROM category"

                << "DROP TABLE IF EXISTS category"
                << "ALTER TABLE category2 RENAME TO category"

                << "DROP TABLE IF EXISTS vm_category_display_tmp"
                << "CREATE TABLE vm_category_display_tmp(  id INT,  t_name TEXT,  t_fullname TEXT,  rd_category_id INT,  i_NBOPERATIONS,  f_REALCURRENTAMOUNT, t_bookmarked)"
                // ============
                << ""
                << "6.9"
                << "7.0"
                << "DELETE FROM parameters WHERE t_name LIKE 'SKG_MONTHLY_REPORT_%'"
                // ============ SKROOGE 1.0.0 ^^^
                << ""
                << "7.0"
                << "7.1"
                << "ALTER TABLE unit ADD COLUMN t_source TEXT NOT NULL DEFAULT ''"
                << "UPDATE unit SET t_source=''"
                // ============
                << ""
                << "7.1"
                << "7.2"
                << "UPDATE unit SET t_source='Yahoo' WHERE t_source='' AND t_internet_code<>''"
                // ============
                << ""
                << "7.2"
                << "7.3"
                << "CREATE TABLE account2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_number TEXT NOT NULL DEFAULT '',"
                "t_agency_number TEXT NOT NULL DEFAULT '',"
                "t_agency_address TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('C', 'D', 'A', 'I', 'L', 'W', 'O')),"
                // C=current D=credit card A=assets (for objects) I=Investment W=Wallet L=Loan O=other
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "rd_bank_id INTEGER NOT NULL)"
                << "INSERT INTO account2 (id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id) "
                "SELECT id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id FROM account"
                << "DROP TABLE IF EXISTS account"
                << "ALTER TABLE account2 RENAME TO account"
                // ============ SKROOGE 1.1.0 ^^^
                << ""
                << "7.3"
                << "7.4"
                << "ALTER TABLE unit ADD COLUMN t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                << "UPDATE unit SET t_bookmarked='N'"
                // ============
                << ""
                << "7.4"
                << "7.5"
                << "DELETE FROM parameters WHERE t_name LIKE 'SKGOPERATION_%'"
                // ============
                << ""
                << "7.5"
                << "7.6"
                << "CREATE TABLE category2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL DEFAULT '' CHECK (t_name NOT LIKE '%" % OBJECTSEPARATOR % "%'),"
                "t_fullname TEXT,"
                "rd_category_id INTEGER NOT NULL DEFAULT 0,"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                ")"
                << "INSERT INTO category2 (id, t_name, t_fullname, rd_category_id, t_bookmarked) "
                "SELECT id, t_name, t_fullname, (CASE WHEN rd_category_id IS NULL OR rd_category_id='' THEN 0 ELSE rd_category_id END), t_bookmarked FROM category"

                << "DROP TABLE IF EXISTS category"
                << "ALTER TABLE category2 RENAME TO category"
                // ============
                << ""
                << "7.6"
                << "7.7"
                << "ALTER TABLE operationbalance ADD COLUMN f_balance_entered FLOAT NOT NULL DEFAULT 0"
                // ============ SKROOGE 1.3.2 ^^^
                << ""
                << "7.7"
                << "7.8"
                << "CREATE TABLE account2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_number TEXT NOT NULL DEFAULT '',"
                "t_agency_number TEXT NOT NULL DEFAULT '',"
                "t_agency_address TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('C', 'D', 'A', 'I', 'L', 'W', 'S', 'O')),"
                // C=current D=credit card A=assets (for objects) I=Investment W=Wallet L=Loan S=Saving O=other
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "rd_bank_id INTEGER NOT NULL)"
                << "INSERT INTO account2 (id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id) "
                "SELECT id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, rd_bank_id FROM account"
                << "DROP TABLE IF EXISTS account"
                << "ALTER TABLE account2 RENAME TO account"
                // ============
                << ""
                << "7.8"
                << "7.9"
                << "DROP TABLE IF EXISTS vm_budget_tmp"
                << "CREATE TABLE vm_budget_tmp(  id INT,  rc_category_id INT,  f_budgeted REAL,  i_year INT,  i_month INT,  f_budgeted_modified REAL,  f_transferred REAL,  t_including_subcategories TEXT,  t_CATEGORY,  t_PERIOD,  f_CURRENTAMOUNT,  t_RULES)"
                << "DROP TABLE IF EXISTS vm_category_display_tmp"
                << "CREATE TABLE vm_category_display_tmp(  id INT,  t_name TEXT,  t_fullname TEXT,  rd_category_id INT,  i_NBOPERATIONS,  f_REALCURRENTAMOUNT, t_bookmarked)"
                // ============ SKROOGE 1.3.3 ^^^
                << ""
                << "7.9"
                << "8.0"
                << "DROP TABLE IF EXISTS operationbalance"
                << "CREATE TABLE operationbalance("
                "r_operation_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "f_balance FLOAT NOT NULL DEFAULT 0,"
                "f_balance_entered FLOAT NOT NULL DEFAULT 0)"
                << ""
                << "8.0"
                << "8.1"
                << "DROP TABLE IF EXISTS operationbalance"
                << "CREATE TABLE operationbalance("
                "r_operation_id INTEGER NOT NULL,"
                "f_balance FLOAT NOT NULL DEFAULT 0,"
                "f_balance_entered FLOAT NOT NULL DEFAULT 0)"
                // ============ SKROOGE 1.4.0 ^^^
                << ""
                << "8.1"
                << "8.2"
                << "DROP TABLE IF EXISTS budgetcategory"
                << "CREATE TABLE budgetsuboperation("
                "id INTEGER NOT NULL DEFAULT 0,"
                "id_suboperation INTEGER NOT NULL DEFAULT 0,"
                "i_priority INTEGER NOT NULL DEFAULT 0)"
                << ""
                << "8.2"
                << "8.3"
                << "DROP TABLE IF EXISTS vm_category_display_tmp"
                << "DROP TRIGGER IF EXISTS fkdc_category_vm_category_display_tmp_id_rd_category_id"
                // ============ SKROOGE 1.7.4 ^^^
                << ""
                << "8.3"
                << "8.4"
                << "ALTER TABLE account ADD COLUMN f_maxamount FLOAT NOT NULL DEFAULT 10000.0"
                << "ALTER TABLE account ADD COLUMN t_maxamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N'))"
                << "ALTER TABLE account ADD COLUMN f_minamount FLOAT NOT NULL DEFAULT 0.0"
                << "ALTER TABLE account ADD COLUMN t_minamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N'))"
                << "UPDATE account SET f_maxamount=10000.0, t_maxamount_enabled='N', f_minamount=0.0, t_minamount_enabled='N'"
                // ============ SKROOGE 1.7.7 ^^^
                << ""
                << "8.4"
                << "8.5"
                << "ALTER TABLE account ADD COLUMN d_reconciliationdate DATE"
                // ============
                << ""
                << "8.5"
                << "8.6"
                << "CREATE TABLE account2("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_name TEXT NOT NULL,"
                "t_number TEXT NOT NULL DEFAULT '',"
                "t_agency_number TEXT NOT NULL DEFAULT '',"
                "t_agency_address TEXT NOT NULL DEFAULT '',"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('C', 'D', 'A', 'I', 'L', 'W', 'S', 'P', 'O')),"
                // C=current D=credit card A=assets (for objects) I=Investment W=Wallet L=Loan S=Saving P=Pension O=other
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "f_maxamount FLOAT NOT NULL DEFAULT 10000.0,"
                "t_maxamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "f_minamount FLOAT NOT NULL DEFAULT 0.0,"
                "t_minamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                "d_reconciliationdate DATE,"
                "rd_bank_id INTEGER NOT NULL)"
                << "INSERT INTO account2 (id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, f_maxamount, t_maxamount_enabled, f_minamount, t_minamount_enabled, d_reconciliationdate, rd_bank_id) "
                "SELECT id, t_name, t_number, t_agency_number, t_agency_address, t_comment, t_close, t_type, t_bookmarked, f_maxamount, t_maxamount_enabled, f_minamount, t_minamount_enabled, d_reconciliationdate, rd_bank_id FROM account"
                << "DROP TABLE IF EXISTS account"
                << "ALTER TABLE account2 RENAME TO account"
                // ============ SKROOGE 1.8.0 ^^^
                << ""
                << "8.6"
                << "8.7"
                << "ALTER TABLE suboperation ADD COLUMN d_date DATE NOT NULL DEFAULT '0000-00-00'"
                << "UPDATE suboperation SET d_date=(SELECT d_date FROM operation WHERE suboperation.rd_operation_id=operation.id)"
                << ""
                << "8.7"
                << "8.8"
                << "UPDATE rule SET t_action_definition=replace(t_action_definition, '\"d_date\"', '\"d_DATEOP\"') WHERE t_action_definition like '%\"d_date\"%'"
                << "UPDATE rule SET t_definition=replace(t_definition, '\"d_date\"', '\"d_DATEOP\"') WHERE t_definition like '%\"d_date\"%'"
                // ============ SKROOGE 1.9.0 ^^^
                << ""
                << "8.8"
                << "8.9"
                << "ALTER TABLE suboperation ADD COLUMN i_order INTEGER NOT NULL DEFAULT 0"
                << "UPDATE suboperation SET i_order=id"
                << ""
                << "8.9"
                << "9.0"
                << "ALTER TABLE account ADD COLUMN r_account_id INTEGER NOT NULL DEFAULT 0"
                << "UPDATE account SET r_account_id=0"
                << ""
                << "9.0"
                << "9.1"
                << "CREATE TABLE rule2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "t_description TEXT NOT NULL DEFAULT '',"
                "t_definition TEXT NOT NULL DEFAULT '',"
                "t_action_description TEXT NOT NULL DEFAULT '',"
                "t_action_definition TEXT NOT NULL DEFAULT '',"
                "t_action_type VARCHAR(1) DEFAULT 'S' CHECK (t_action_type IN ('S', 'U', 'A', 'T')),"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "f_sortorder FLOAT"
                ")"
                << "INSERT INTO rule2 (id, t_description, t_definition, t_action_description, t_action_definition, t_action_type, t_bookmarked,f_sortorder) SELECT id, t_description, t_definition, t_action_description, t_action_definition, t_action_type, t_bookmarked,f_sortorder FROM rule"
                << "DROP TABLE IF EXISTS rule"
                << "ALTER TABLE rule2 RENAME TO rule"
                << ""
                << "9.1"
                << "9.2"
                << "UPDATE parameters SET t_value=replace(t_value, ' limitVisible=&amp;amp;quot;Y&amp;amp;quot; ', ' limitVisible=&amp;amp;quot;Y&amp;amp;quot; averageVisible=&amp;amp;quot;Y&amp;amp;quot; ')"
                << "UPDATE parameters SET t_value=replace(t_value, ' limitVisible=&amp;amp;quot;N&amp;amp;quot; ', ' limitVisible=&amp;amp;quot;N&amp;amp;quot; averageVisible=&amp;amp;quot;N&amp;amp;quot; ')"
                << ""
                << "9.2"
                << "9.3"
                << "CREATE TABLE operation2 ("
                "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                "i_group_id INTEGER NOT NULL DEFAULT 0,"
                "i_number INTEGER DEFAULT 0 CHECK (i_number>=0),"
                "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                "d_createdate DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,"
                "rd_account_id INTEGER NOT NULL,"
                "t_mode TEXT NOT NULL DEFAULT '',"
                "r_payee_id INTEGER NOT NULL DEFAULT 0,"
                "t_comment TEXT NOT NULL DEFAULT '',"
                "rc_unit_id INTEGER NOT NULL,"
                "t_status VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_status IN ('N', 'P', 'Y')),"
                "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                "t_imported VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_imported IN ('Y', 'N', 'P', 'T')),"
                "t_template VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_template IN ('Y', 'N')),"
                "t_import_id TEXT NOT NULL DEFAULT '',"
                "i_tmp INTEGER NOT NULL DEFAULT 0,"
                "r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0)"
                << "INSERT INTO operation2 (id, i_group_id, i_number, d_date, d_createdate, rd_account_id, t_mode, r_payee_id, t_comment,"
                "rc_unit_id, t_status, t_bookmarked, t_imported, t_template, t_import_id, i_tmp, r_recurrentoperation_id) "
                "SELECT id, i_group_id, i_number, d_date, CURRENT_TIMESTAMP, rd_account_id, t_mode, r_payee_id, t_comment,"
                "rc_unit_id, t_status, t_bookmarked, t_imported, t_template, t_import_id, i_tmp, r_recurrentoperation_id FROM operation"
                << "DROP TABLE IF EXISTS operation"
                << "ALTER TABLE operation2 RENAME TO operation";
    }

    {
        int nbSteps = migrationSteps.count();
        SKGBEGINPROGRESSTRANSACTION(*this, "#INTERNAL#" % i18nc("Progression step", "Migrate document"), err, 5);
        IFOK(err) {
            QString version = getParameter("SKG_DB_BANK_VERSION");
            QString initialversion = version;
            QString lastversion = "9.3";
            if (version.isEmpty()) {
                SKGTRACEL(10) << "Initial creation" << endl;
                /**
                 * This constant is used to initialized the data model.
                 * Rules for attribute name:
                 *    t_xxx for TEXT and VARCHAR
                 *    d_xxx for DATE
                 *    f_xxx for FLOAT
                 *    i_xxx for INTEGER
                 *    r_xxx for a link without constraint
                 *    rc_pointed_table_pointed_attribute_xxx for link on other an object in named "pointed_table" with "pointed_attribute"=id of pointing object
                 *                                       a constraint will be created without DELETE CASCADE
                 *    rd_pointed_table_pointed_attribute_xxx for link on other an object in named "pointed_table" with "pointed_attribute"=id of pointing object
                 *                                       a constraint will be created with DELETE CASCADE
                 *    xxx must be in lower case for R/W attributes and in upper case for R/O attributes
                 * Rules for table name:
                 *    v_yyy for views
                 */
                QStringList BankInitialDataModel;
                BankInitialDataModel
                // ==================================================================
                // Table unit
                        << "CREATE TABLE unit("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL,"
                        "t_symbol TEXT NOT NULL DEFAULT '',"
                        "t_country TEXT NOT NULL DEFAULT '',"
                        "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('1', '2', 'C', 'S', 'I', 'O')),"
                        // 1=main currency, 2=secondary currency, C=currencies S=share, I=index, O=object
                        "t_internet_code TEXT NOT NULL DEFAULT '',"
                        "i_nbdecimal INT NOT NULL DEFAULT 2,"
                        "rd_unit_id INTEGER NOT NULL DEFAULT 0,"
                        "t_source TEXT NOT NULL DEFAULT '',"
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                        ")"

                        // ==================================================================
                        // Table unitvalue
                        << "CREATE TABLE unitvalue("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "rd_unit_id INTEGER NOT NULL,"
                        "d_date DATE NOT NULL,"
                        "f_quantity FLOAT NOT NULL CHECK (f_quantity>=0))"

                        // ==================================================================
                        // Table bank
                        << "CREATE TABLE bank ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL DEFAULT '',"
                        "t_bank_number TEXT NOT NULL DEFAULT '',"
                        "t_icon TEXT NOT NULL DEFAULT '')"

                        // ==================================================================
                        // Table account
                        << "CREATE TABLE account("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL,"
                        "t_number TEXT NOT NULL DEFAULT '',"
                        "t_agency_number TEXT NOT NULL DEFAULT '',"
                        "t_agency_address TEXT NOT NULL DEFAULT '',"
                        "t_comment TEXT NOT NULL DEFAULT '',"
                        "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                        "t_type VARCHAR(1) NOT NULL DEFAULT 'C' CHECK (t_type IN ('C', 'D', 'A', 'I', 'L', 'W', 'S', 'P', 'O')),"
                        // C=current D=credit card A=assets (for objects) I=Investment W=Wallet L=Loan S=Saving P=Pension O=other
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                        "f_maxamount FLOAT NOT NULL DEFAULT 10000.0,"
                        "t_maxamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                        "f_minamount FLOAT NOT NULL DEFAULT 0.0,"
                        "t_minamount_enabled VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')),"
                        "d_reconciliationdate DATE,"
                        "r_account_id INTEGER NOT NULL DEFAULT 0,"
                        "rd_bank_id INTEGER NOT NULL)"

                        // ==================================================================
                        // Table interest
                        << "CREATE TABLE interest("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "rd_account_id INTEGER NOT NULL,"
                        "d_date DATE NOT NULL,"
                        "f_rate FLOAT NOT NULL CHECK (f_rate>=0),"
                        "t_income_value_date_mode VARCHAR(1) NOT NULL DEFAULT 'F' CHECK (t_income_value_date_mode IN ('F', '0', '1', '2', '3', '4', '5')),"
                        "t_expenditure_value_date_mode VARCHAR(1) NOT NULL DEFAULT 'F' CHECK (t_expenditure_value_date_mode IN ('F', '0', '1', '2', '3', '4', '5')),"
                        "t_base VARCHAR(3) NOT NULL DEFAULT '24' CHECK (t_base IN ('24', '360', '365'))"
                        ")"

                        // ==================================================================
                        // Table category
                        << "CREATE TABLE category ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL DEFAULT '' CHECK (t_name NOT LIKE '%" % OBJECTSEPARATOR % "%'),"
                        "t_fullname TEXT,"
                        "rd_category_id INTEGER NOT NULL DEFAULT 0,"
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                        ")"

                        // ==================================================================
                        // Table operation
                        << "CREATE TABLE operation("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "i_group_id INTEGER NOT NULL DEFAULT 0,"
                        "i_number INTEGER DEFAULT 0 CHECK (i_number>=0),"
                        "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                        "d_createdate DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,"
                        "rd_account_id INTEGER NOT NULL,"
                        "t_mode TEXT NOT NULL DEFAULT '',"
                        "r_payee_id INTEGER NOT NULL DEFAULT 0,"
                        "t_comment TEXT NOT NULL DEFAULT '',"
                        "rc_unit_id INTEGER NOT NULL,"
                        "t_status VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_status IN ('N', 'P', 'Y')),"
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                        "t_imported VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_imported IN ('Y', 'N', 'P', 'T')),"
                        "t_template VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_template IN ('Y', 'N')),"
                        "t_import_id TEXT NOT NULL DEFAULT '',"
                        "i_tmp INTEGER NOT NULL DEFAULT 0,"
                        "r_recurrentoperation_id INTEGER NOT NULL DEFAULT 0)"

                        << "CREATE TABLE operationbalance("
                        "r_operation_id INTEGER NOT NULL,"
                        "f_balance FLOAT NOT NULL DEFAULT 0,"
                        "f_balance_entered FLOAT NOT NULL DEFAULT 0)"

                        // ==================================================================
                        // Table refund
                        << "CREATE TABLE refund ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL DEFAULT '',"
                        "t_comment TEXT NOT NULL DEFAULT '',"
                        "t_close VARCHAR(1) DEFAULT 'N' CHECK (t_close IN ('Y', 'N')))"

                        // ==================================================================
                        // Table payee
                        << "CREATE TABLE payee ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_name TEXT NOT NULL DEFAULT '',"
                        "t_address TEXT NOT NULL DEFAULT '',"
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N'))"
                        ")"

                        // ==================================================================
                        // Table suboperation
                        << "CREATE TABLE suboperation("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                        "t_comment TEXT NOT NULL DEFAULT '',"
                        "rd_operation_id INTEGER NOT NULL,"
                        "r_category_id INTEGER NOT NULL DEFAULT 0,"
                        "f_value FLOAT NOT NULL DEFAULT 0.0,"
                        "t_formula TEXT NOT NULL DEFAULT '',"
                        "i_tmp INTEGER NOT NULL DEFAULT 0,"
                        "r_refund_id INTEGER NOT NULL DEFAULT 0,"
                        "i_order INTEGER NOT NULL DEFAULT 0"
                        ")"

                        // ==================================================================
                        // Table recurrentoperation
                        << "CREATE TABLE recurrentoperation ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "d_date DATE NOT NULL DEFAULT '0000-00-00',"
                        "rd_operation_id INTEGER NOT NULL,"
                        "i_period_increment INTEGER NOT NULL DEFAULT 1 CHECK (i_period_increment>=0),"
                        "t_period_unit TEXT NOT NULL DEFAULT 'M' CHECK (t_period_unit IN ('D', 'W', 'M', 'Y')),"
                        "t_auto_write VARCHAR(1) DEFAULT 'Y' CHECK (t_auto_write IN ('Y', 'N')),"
                        "i_auto_write_days INTEGER NOT NULL DEFAULT 5 CHECK (i_auto_write_days>=0),"
                        "t_warn VARCHAR(1) DEFAULT 'Y' CHECK (t_warn IN ('Y', 'N')),"
                        "i_warn_days INTEGER NOT NULL DEFAULT 5 CHECK (i_warn_days>=0),"
                        "t_times VARCHAR(1) DEFAULT 'N' CHECK (t_times IN ('Y', 'N')),"
                        "i_nb_times INTEGER NOT NULL DEFAULT 1 CHECK (i_nb_times>=0)"
                        ")"

                        // ==================================================================
                        // Table rule
                        << "CREATE TABLE rule ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "t_description TEXT NOT NULL DEFAULT '',"
                        "t_definition TEXT NOT NULL DEFAULT '',"
                        "t_action_description TEXT NOT NULL DEFAULT '',"
                        "t_action_definition TEXT NOT NULL DEFAULT '',"
                        "t_action_type VARCHAR(1) DEFAULT 'S' CHECK (t_action_type IN ('S', 'U', 'A', 'T')),"
                        "t_bookmarked VARCHAR(1) NOT NULL DEFAULT 'N' CHECK (t_bookmarked IN ('Y', 'N')),"
                        "f_sortorder FLOAT"
                        ")"

                        // ==================================================================
                        // Table budget
                        << "CREATE TABLE budget ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "rc_category_id INTEGER NOT NULL DEFAULT 0,"
                        "t_including_subcategories TEXT NOT NULL DEFAULT 'N' CHECK (t_including_subcategories IN ('Y', 'N')),"
                        "f_budgeted FLOAT NOT NULL DEFAULT 0.0,"
                        "f_budgeted_modified FLOAT NOT NULL DEFAULT 0.0,"
                        "f_transferred FLOAT NOT NULL DEFAULT 0.0,"
                        "i_year INTEGER NOT NULL DEFAULT 2010,"
                        "i_month INTEGER NOT NULL DEFAULT 0 CHECK (i_month>=0 AND i_month<=12)"
                        ")"

                        << "CREATE TABLE budgetsuboperation("
                        "id INTEGER NOT NULL DEFAULT 0,"
                        "id_suboperation INTEGER NOT NULL DEFAULT 0,"
                        "i_priority INTEGER NOT NULL DEFAULT 0)"

                        << "CREATE TABLE budgetrule ("
                        "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
                        "rc_category_id INTEGER NOT NULL DEFAULT 0,"
                        "t_category_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_category_condition IN ('Y', 'N')),"
                        "t_year_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_year_condition IN ('Y', 'N')),"
                        "i_year INTEGER NOT NULL DEFAULT 2010,"
                        "i_month INTEGER NOT NULL DEFAULT 0 CHECK (i_month>=0 AND i_month<=12),"
                        "t_month_condition TEXT NOT NULL DEFAULT 'Y' CHECK (t_month_condition IN ('Y', 'N')),"
                        "i_condition INTEGER NOT NULL DEFAULT 0 CHECK (i_condition IN (-1,0,1)),"
                        "f_quantity FLOAT NOT NULL DEFAULT 0.0,"
                        "t_absolute TEXT NOT NULL DEFAULT 'Y' CHECK (t_absolute IN ('Y', 'N')),"
                        "rc_category_id_target INTEGER NOT NULL DEFAULT 0,"
                        "t_category_target TEXT NOT NULL DEFAULT 'Y' CHECK (t_category_target IN ('Y', 'N')),"
                        "t_rule TEXT NOT NULL DEFAULT 'N' CHECK (t_rule IN ('N', 'C', 'Y'))"
                        ")"

                        << "CREATE TABLE vm_budget_tmp(  id INT,  rc_category_id INT,  f_budgeted REAL,  i_year INT,  i_month INT,  f_budgeted_modified REAL,  f_transferred REAL,  t_including_subcategories TEXT,  t_CATEGORY,  t_PERIOD,  f_CURRENTAMOUNT,  t_RULES)";

                IFOKDO(err, this->executeSqliteOrders(BankInitialDataModel))

                // Set new version
                version = lastversion;
                IFOKDO(err, SKGDocument::setParameter("SKG_DB_BANK_VERSION", version))
            }

            if (!err && SKGServices::stringToDouble(version) > SKGServices::stringToDouble(lastversion)) {
                err = SKGError(ERR_ABORT, i18nc("Error message", "Impossible to load a document generated by a more recent version"));
            }

            IFOK(err) {
                QString v1;
                QString v2;
                bool computeCaches = false;
                for (int i = 0; !err && i < nbSteps; ++i) {
                    if (migrationSteps.at(i).isEmpty()) {
                        ++i;
                        v1 = migrationSteps.at(i);
                        ++i;
                        v2 = migrationSteps.at(i);
                        if (version == v1) {
                            SKGTRACEL(10) << "Migration from " << v1 << " to " << v2 << endl;
                            for (int j = i + 1; !err && j < nbSteps; ++j) {
                                QString sql = migrationSteps.at(j);
                                if (!sql.isEmpty()) {
                                    ++i;
                                    IFOKDO(err, this->executeSqliteOrder(sql))
                                } else {
                                    break;
                                }
                            }

                            if (v1 == "4.7" || v1 == "5.1" || v1 == "5.7" || v1 == "5.9" || v1 == "8.0" || v1 == "8.1") {
                                computeCaches = true;
                            }

                            // Set new version
                            version = v2;
                            IFOKDO(err, SKGDocument::setParameter("SKG_DB_BANK_VERSION", version))
                            oMigrationDone = true;
                        }
                    }
                }
                IFOKDO(err, stepForward(1, i18nc("Progression step", "Refresh views")))

                if (!err && computeCaches) {
                    err = refreshViewsIndexesAndTriggers();
                    IFOKDO(err, stepForward(2, i18nc("Progression step", "Computation of balances")))
                    IFOKDO(err, computeBalances())
                    IFOKDO(err, stepForward(3, i18nc("Progression step", "Computation of budgets")))
                    IFOKDO(err, computeBudgetSuboperationLinks())
                    IFOKDO(err, stepForward(4))
                }

                IFOK(err) {
                    bool mig = false;
                    err = SKGDocument::migrate(mig);
                    oMigrationDone = oMigrationDone | mig;
                } else {
                    err.addError(ERR_FAIL, i18nc("Error message: Could not perform database migration", "Database migration from version %1 to version %2 failed", initialversion, version));
                }
                IFOKDO(err, stepForward(5))
            }
        }
    }

    return err;
}

SKGError SKGDocumentBank::dump(int iMode)
{
    SKGError err;
    if (Q_LIKELY(getDatabase())) {
        // dump parameters
        SKGTRACE << "=== START DUMP BANK DOCUMENT ===" << endl;
        err = SKGDocument::dump(iMode);

        if (iMode & DUMPUNIT) {
            SKGTRACE << "=== DUMPUNIT (UNITS))===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_unit_display ORDER BY id"));

            SKGTRACE << "=== DUMPUNIT (VALUES) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_unitvalue_display ORDER BY rd_unit_id, d_date"));
        }

        if (iMode & DUMPACCOUNT) {
            SKGTRACE << "=== DUMPACCOUNT (BANKS) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_bank ORDER BY id"));

            SKGTRACE << "=== DUMPACCOUNT (ACCOUNTS) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_account_display ORDER BY rd_bank_id, id"));
        }

        if (iMode & DUMPOPERATION) {
            SKGTRACE << "=== DUMPOPERATION (OPERATIONS) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_operation_display_all ORDER BY id"));

            SKGTRACE << "=== DUMPOPERATION (SUBOPERATIONS) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_suboperation_display ORDER BY rd_operation_id, id"));

            SKGTRACE << "=== DUMPOPERATION (RECURRENT) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_recurrentoperation ORDER BY rd_operation_id, id"));

            SKGTRACE << "=== DUMPOPERATION (TRACKER) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_refund ORDER BY id"));
        }

        if (iMode & DUMPPAYEE) {
            SKGTRACE << "=== DUMPOPERATION (PAYEE) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_payee ORDER BY id"));
        }

        if (iMode & DUMPCATEGORY) {
            SKGTRACE << "=== DUMPCATEGORY ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_category_display ORDER BY rd_category_id, id"));
        }

        if (iMode & DUMPBUDGET) {
            SKGTRACE << "=== DUMPBUDGET (BUDGET) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_budget_display ORDER BY t_PERIOD"));

            SKGTRACE << "=== DUMPBUDGET (RULES) ===" << endl;
            err.addError(dumpSelectSqliteOrder("SELECT * FROM v_budgetrule_display ORDER BY t_absolute DESC, id"));
        }

        SKGTRACE << "=== END DUMP BANK DOCUMENT ===" << endl;
    }

    return err;
}

SKGError SKGDocumentBank::addOrModifyUnitValue(const QString& iUnitName, const QDate& iDate, double iValue, SKGUnitValueObject* oValue)
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);

    // Creation or update of the unit
    bool insertOrUpdate = true;
    SKGUnitObject unit(this);
    err = unit.setName(iUnitName);
    IFOKDO(err, unit.setSymbol(iUnitName))
    if (!unit.exist()) {
        insertOrUpdate = false;
        IFOKDO(err, unit.save(insertOrUpdate))
    } else {
        err = unit.load();
    }

    // Creation or update of the value
    SKGUnitValueObject value;
    IFOKDO(err, unit.addUnitValue(value))
    IFOKDO(err, value.setDate(iDate))
    IFOKDO(err, value.setQuantity(iValue))
    IFOKDO(err, value.save(insertOrUpdate))

    if (oValue) {
        *oValue = value;
    }

    // Add error if needed
    IFKO(err) err.addError(ERR_FAIL, i18nc("Error message",  "Operation '%1' on '%2' failed", QString("SKGDocumentBank::addOrModifyUnitValue"),
                                           iUnitName % " / " % SKGServices::dateToSqlString(QDateTime(iDate)) % " / " % SKGServices::doubleToString(iValue)));
    return err;
}

SKGServices::SKGUnitInfo SKGDocumentBank::getPrimaryUnit()
{
    SKGServices::SKGUnitInfo output;

    output.Name = getCachedValue("primaryUnitCache");
    if (output.Name.isEmpty()) {
        this->refreshCache("unit");
        output.Name = getCachedValue("primaryUnitCache");
    }
    output.Value = 1;
    output.Symbol = getCachedValue("primaryUnitSymbolCache");
    output.NbDecimal = SKGServices::stringToInt(getCachedValue("primaryUnitDecimalCache"));

    return output;
}

SKGServices::SKGUnitInfo SKGDocumentBank::getSecondaryUnit()
{
    SKGServices::SKGUnitInfo output;

    output.Name = getCachedValue("secondaryUnitCache");
    if (output.Name.isEmpty()) {
        this->refreshCache("unit");
        output.Name = getCachedValue("secondaryUnitCache");
    }
    output.Symbol = getCachedValue("secondaryUnitSymbolCache");
    output.Value = SKGServices::stringToDouble(getCachedValue("secondaryUnitValueCache"));
    output.NbDecimal = SKGServices::stringToInt(getCachedValue("secondaryUnitDecimalCache"));

    return output;
}

void SKGDocumentBank::refreshCache(const QString& iTable)
{
    if (iTable == "unit") {
        SKGStringListList result;
        executeSelectSqliteOrder("SELECT t_name, t_symbol, i_nbdecimal FROM unit WHERE t_type='1'", result);
        if (result.size() == 2) {
            addValueInCache("primaryUnitCache", result.at(1).at(0));
            addValueInCache("primaryUnitSymbolCache", result.at(1).at(1));
            addValueInCache("primaryUnitDecimalCache", result.at(1).at(2));
        } else {
            addValueInCache("primaryUnitCache", "");
            addValueInCache("primaryUnitSymbolCache", "");
            addValueInCache("primaryUnitDecimalCache", "2");
        }

        executeSelectSqliteOrder("SELECT t_name, t_symbol, f_CURRENTAMOUNT, i_nbdecimal FROM v_unit WHERE t_type='2'", result);
        if (result.size() == 2) {
            addValueInCache("secondaryUnitCache", result.at(1).at(0));
            addValueInCache("secondaryUnitSymbolCache", result.at(1).at(1));
            addValueInCache("secondaryUnitValueCache", result.at(1).at(2));
            addValueInCache("secondaryUnitDecimalCache", result.at(1).at(3));
        } else {
            addValueInCache("secondaryUnitCache", "");
            addValueInCache("secondaryUnitSymbolCache", "");
            addValueInCache("secondaryUnitValueCache", "1");
            addValueInCache("secondaryUnitDecimalCache", "2");
        }
    }
}

SKGError SKGDocumentBank::addOrModifyAccount(const QString& iName, const QString& iNumber, const QString& iBankName)
{
    SKGError err;
    SKGTRACEINFUNCRC(10, err);

    // Creation or update of the bank
    SKGBankObject bank(this);
    err = bank.setName(iBankName);
    IFOKDO(err, bank.save())

    // Creation or update of the account
    SKGAccountObject account;
    IFOKDO(err, bank.addAccount(account))
    IFOKDO(err, account.setAttribute("rd_bank_id", SKGServices::intToString(bank.getID())))
    IFOKDO(err, account.setName(iName))
    IFOKDO(err, account.setAttribute("t_number", iNumber))
    IFOKDO(err, account.save())

    IFKO(err) err.addError(ERR_FAIL, i18nc("Error message",  "Operation '%1' on '%2' failed", QString("SKGDocumentBank::addOrModifyAccount"), iName));
    return err;
}

QString SKGDocumentBank::getFileExtension() const
{
    return "skg";
}

QString SKGDocumentBank::getDocumentHeader() const
{
    return "SKROOGE";
}

QList<SKGDocument::SKGModelTemplate> SKGDocumentBank::getDisplaySchemas(const QString& iRealTable) const
{
    QList<SKGDocument::SKGModelTemplate> listSchema;

    // Get properties
    QStringList properties;
    QString tableForProperties = iRealTable;
    if (tableForProperties == "suboperation") {
        tableForProperties = "operation";
    }
    this->getDistinctValues("parameters", "t_name", "(t_uuid_parent like '%-" % tableForProperties % "' OR t_uuid_parent like '%-sub" % tableForProperties % "') AND t_name NOT LIKE 'SKG_%'", properties);

    // Build property schema
    QString propSchema;
    int nb = properties.count();
    for (int i = 0; i < nb; ++i) {
        propSchema += ";p_" % properties.at(i) % "|N";
    }

    // Build schemas
    if (iRealTable == "operation" || iRealTable == "suboperation") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "d_date;i_NBRECURRENT;t_bookmarked;t_ACCOUNT;t_TOACCOUNT|N;i_number;t_mode;t_PAYEE;t_comment;t_REALCOMMENT;t_CATEGORY;t_REALCATEGORY;t_status;"
                     "f_REALCURRENTAMOUNT;f_REALCURRENTAMOUNT_EXPENSE|N;f_REALCURRENTAMOUNT_INCOME|N;"
                     "f_CURRENTAMOUNT;f_CURRENTAMOUNT_EXPENSE|N;f_CURRENTAMOUNT_INCOME|N;"
                     "f_QUANTITY|N;f_QUANTITY_EXPENSE|N;f_QUANTITY_INCOME|N;f_REALQUANTITY|N;f_REALQUANTITY_EXPENSE|N;f_REALQUANTITY_INCOME|N;"
                     "t_imported|N;t_REALREFUND|N;t_REFUND|N"
                     ";f_BALANCE|N;f_BALANCE_ENTERED|N;d_createdate|N" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "d_date;i_NBRECURRENT|N;t_bookmarked|N;t_ACCOUNT;t_TOACCOUNT|N;i_number|N;t_mode|N;t_PAYEE|N;t_comment|N;t_REALCOMMENT|N;t_CATEGORY|N;t_REALCATEGORY|N;t_status;"
                         "f_REALCURRENTAMOUNT;f_REALCURRENTAMOUNT_EXPENSE|N;f_REALCURRENTAMOUNT_INCOME|N;"
                         "f_CURRENTAMOUNT;f_CURRENTAMOUNT_EXPENSE|N;f_CURRENTAMOUNT_INCOME|N;"
                         "f_QUANTITY|N;f_QUANTITY_EXPENSE|N;f_QUANTITY_INCOME|N;f_REALQUANTITY|N;f_REALQUANTITY_EXPENSE|N;f_REALQUANTITY_INCOME|N;"
                         "t_imported|N;t_REALREFUND|N;t_REFUND|N"
                         ";f_BALANCE|N;f_BALANCE_ENTERED|N;d_createdate|N" % propSchema;
        listSchema.push_back(minimum);

        SKGModelTemplate doubleColumn;
        doubleColumn.id = "doublecolumn";
        doubleColumn.name = i18nc("Noun",  "Amount in 2 columns");
        doubleColumn.icon = "";
        doubleColumn.schema = "d_date;i_NBRECURRENT;t_bookmarked;t_ACCOUNT;t_TOACCOUNT|N;i_number;t_mode;t_PAYEE;t_comment;t_REALCOMMENT;t_CATEGORY;t_REALCATEGORY;t_status;"
                              "f_REALCURRENTAMOUNT|N;f_REALCURRENTAMOUNT_EXPENSE|Y;f_REALCURRENTAMOUNT_INCOME|Y;"
                              "f_CURRENTAMOUNT|N;f_CURRENTAMOUNT_EXPENSE|Y;f_CURRENTAMOUNT_INCOME|Y;"
                              "f_QUANTITY|N;f_QUANTITY_EXPENSE|N;f_QUANTITY_INCOME|N;f_REALQUANTITY|N;f_REALQUANTITY_EXPENSE|N;f_REALQUANTITY_INCOME|N;"
                              "t_imported|N;t_REALREFUND|N;t_REFUND|N"
                              ";f_BALANCE|N;f_BALANCE_ENTERED|N;d_createdate|N" % propSchema;
        listSchema.push_back(doubleColumn);

        SKGModelTemplate amountEntered;
        amountEntered.id = "amountentered";
        amountEntered.name = i18nc("Noun",  "Amount entered");
        amountEntered.icon = "";
        amountEntered.schema = "d_date;i_NBRECURRENT;t_bookmarked;t_ACCOUNT;t_TOACCOUNT|N;i_number;t_mode;t_PAYEE;t_comment;t_REALCOMMENT;t_CATEGORY;t_REALCATEGORY;t_status;"
                               "f_REALCURRENTAMOUNT|N;f_REALCURRENTAMOUNT_EXPENSE|N;f_REALCURRENTAMOUNT_INCOME|N;"
                               "f_CURRENTAMOUNT|N;f_CURRENTAMOUNT_EXPENSE|N;f_CURRENTAMOUNT_INCOME|N;"
                               "f_QUANTITY|Y;f_QUANTITY_EXPENSE|N;f_QUANTITY_INCOME|N;f_REALQUANTITY|Y;f_REALQUANTITY_EXPENSE|N;f_REALQUANTITY_INCOME|N;"
                               "t_imported|N;t_REALREFUND|N;t_REFUND|N"
                               ";f_BALANCE|N;f_BALANCE_ENTERED|N;d_createdate|N" % propSchema;
        listSchema.push_back(amountEntered);

        SKGModelTemplate doubleColumnEntered;
        doubleColumnEntered.id = "doublecolumnentered";
        doubleColumnEntered.name = i18nc("Noun",  "Amount entered in 2 columns");
        doubleColumnEntered.icon = "";
        doubleColumnEntered.schema = "d_date;i_NBRECURRENT;t_bookmarked;t_ACCOUNT;t_TOACCOUNT|N;i_number;t_mode;t_PAYEE;t_comment;t_REALCOMMENT;t_CATEGORY;t_REALCATEGORY;t_status;"
                                     "f_REALCURRENTAMOUNT|N;f_REALCURRENTAMOUNT_EXPENSE|N;f_REALCURRENTAMOUNT_INCOME|N;"
                                     "f_CURRENTAMOUNT|N;f_CURRENTAMOUNT_EXPENSE|N;f_CURRENTAMOUNT_INCOME|N;"
                                     "f_QUANTITY|N;f_QUANTITY_EXPENSE|Y;f_QUANTITY_INCOME|Y;f_REALQUANTITY|N;f_REALQUANTITY_EXPENSE|Y;f_REALQUANTITY_INCOME|Y;"
                                     "t_imported|N;t_REALREFUND|N;t_REFUND|N"
                                     ";f_BALANCE|N;f_BALANCE_ENTERED|N;d_createdate|N" % propSchema;
        listSchema.push_back(doubleColumnEntered);
    } else if (iRealTable == "recurrentoperation") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "d_date;t_PERIODNLS;i_nb_times;i_auto_write_days;i_warn_days;t_ACCOUNT;i_number;t_mode;t_PAYEE;t_comment;t_CATEGORY;"
                     "t_status;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "d_date;t_PERIODNLS;i_nb_times;i_auto_write_days;i_warn_days;t_ACCOUNT;i_number|N;t_mode|N;t_PAYEE;t_comment|N;t_CATEGORY|N;"
                         "t_status;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "account") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_BANK;t_close;t_bookmarked;t_name;t_TYPENLS;t_BANK_NUMBER;t_agency_number;t_number;t_agency_address;t_comment;f_CURRENTAMOUNT;f_QUANTITY|N;f_TODAYAMOUNT|N;f_CHECKED;f_COMING_SOON;d_reconciliationdate|N;i_NBOPERATIONS;f_RATE|N" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_BANK;t_close;t_bookmarked|N;t_name;t_TYPENLS|N;t_BANK_NUMBER|N;t_agency_number|N;t_number|N;t_agency_address|N;t_comment|N;f_CURRENTAMOUNT|N;f_QUANTITY|N;f_TODAYAMOUNT|N;f_CHECKED|N;f_COMING_SOON|N;d_reconciliationdate|N;i_NBOPERATIONS|N;f_RATE|N" % propSchema;
        listSchema.push_back(minimum);

        SKGModelTemplate intermediate;
        intermediate.id = "intermediate";
        intermediate.name = i18nc("Noun, an intermediate value between two extremums", "Intermediate");
        intermediate.icon = "";
        intermediate.schema = "t_BANK;t_close;t_bookmarked;t_name;t_TYPENLS|N;t_BANK_NUMBER|N;t_agency_number|N;t_number|N;t_agency_address|N;t_comment|N;f_CURRENTAMOUNT;f_QUANTITY|N;f_TODAYAMOUNT|N,f_CHECKED;f_COMING_SOON;d_reconciliationdate|N;i_NBOPERATIONS|N;f_RATE|N" % propSchema;
        listSchema.push_back(intermediate);
    } else if (iRealTable == "category") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_name;t_bookmarked;i_NBOPERATIONS;f_REALCURRENTAMOUNT;i_SUMNBOPERATIONS;f_SUMCURRENTAMOUNT" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_name;t_bookmarked;i_NBOPERATIONS|N;f_REALCURRENTAMOUNT|N;i_SUMNBOPERATIONS|N;f_SUMCURRENTAMOUNT|N" % propSchema;
        listSchema.push_back(minimum);

        SKGModelTemplate op;
        op.id = "with_operations";
        op.name = i18nc("Noun",  "With operations");
        op.icon = "";
        op.schema = "t_name;t_bookmarked;i_NBOPERATIONS;f_REALCURRENTAMOUNT;i_SUMNBOPERATIONS|N;f_SUMCURRENTAMOUNT|N" % propSchema;
        listSchema.push_back(op);

        SKGModelTemplate op2;
        op2.id = "with_cumulative_operations";
        op2.name = i18nc("Noun",  "With cumulative operations");
        op2.icon = "";
        op2.schema = "t_name;t_bookmarked;i_NBOPERATIONS|N;f_REALCURRENTAMOUNT|N;i_SUMNBOPERATIONS;f_SUMCURRENTAMOUNT" % propSchema;
        listSchema.push_back(op2);
    } else if (iRealTable == "unit") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_name;t_symbol;t_bookmarked;t_country;t_TYPENLS;t_source;t_internet_code;f_CURRENTAMOUNT;f_QUANTITYOWNED;f_AMOUNTOWNED;i_nbdecimal;t_UNIT;d_MAXDATE|N" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_name;t_symbol;t_bookmarked|N;t_country|N;t_TYPENLS;t_source|N;t_internet_code|N;f_CURRENTAMOUNT|N;f_QUANTITYOWNED|N;f_AMOUNTOWNED|N;i_nbdecimal|N;t_UNIT|N;d_MAXDATE|N" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "unitvalue") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "d_date;f_quantity;t_UNIT|N" % propSchema;
        listSchema.push_back(def);
    } else if (iRealTable == "refund") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_name;t_comment;t_close;d_FIRSTDATE;d_LASTDATE;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_name;t_comment|N;t_close;d_FIRSTDATE|N;d_LASTDATE|N;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "payee") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_name;t_bookmarked;t_address;i_NBOPERATIONS|N;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_name;t_bookmarked;t_address|N;i_NBOPERATIONS|N;f_CURRENTAMOUNT" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "rule") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "i_ORDER;t_bookmarked;t_action_type;t_description;t_action_description" % propSchema;
        listSchema.push_back(def);
    } else if (iRealTable == "interest") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "d_date;f_rate;t_income_value_date_mode;t_expenditure_value_date_mode;t_base" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "d_date;f_rate;t_income_value_date_mode|N;t_expenditure_value_date_mode|N;t_base|N" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "interest_result") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "d_date;d_valuedate;t_comment;f_currentamount;f_coef;f_rate;f_annual_interest;f_accrued_interest" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "d_date;d_valuedate|N;t_comment|N;f_currentamount|N;f_coef|N;f_rate;f_annual_interest;f_accrued_interest|N" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "budget") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_CATEGORY;t_PERIOD;i_year|N;i_month|N;f_budgeted;f_budgeted_modified;f_CURRENTAMOUNT;f_DELTABEFORETRANSFER|N;t_RULES;f_DELTA" % propSchema;
        listSchema.push_back(def);

        SKGModelTemplate minimum;
        minimum.id = "minimum";
        minimum.name = i18nc("Noun, the minimum value of an item", "Minimum");
        minimum.icon = "";
        minimum.schema = "t_CATEGORY;t_PERIOD;i_year|N;i_month|N;f_budgeted|N;f_budgeted_modified;f_CURRENTAMOUNT;f_DELTABEFORETRANSFER;t_RULES|N;f_DELTA|N" % propSchema;
        listSchema.push_back(minimum);
    } else if (iRealTable == "budgetrule") {
        SKGModelTemplate def;
        def.id = "default";
        def.name = i18nc("Noun, the default value of an item", "Default");
        def.icon = "edit-undo";
        def.schema = "t_CATEGORYCONDITION;i_year;i_month;t_WHENNLS;t_WHATNLS;t_RULENLS;t_CATEGORY" % propSchema;
        listSchema.push_back(def);
    } else {
        listSchema = SKGDocument::getDisplaySchemas(iRealTable);
    }

    return listSchema;
}

QIcon SKGDocumentBank::getIcon(const QString& iString) const
{
    QString att = iString.toLower();

    if (att.endsWith(QLatin1String("t_bookmarked"))) {
        return KIcon("bookmarks");
    }
    if (att.endsWith(QLatin1String("f_balance")) ||
        att.endsWith(QLatin1String("f_balance_entered"))) {
        return KIcon("office-chart-line");
    }
    if (att.endsWith(QLatin1String("i_nbrecurrent"))) {
        return KIcon("chronometer");
    }
    if (att.endsWith(QLatin1String("t_status")) ||
        att.endsWith(QLatin1String("f_checked")) ||
        att.endsWith(QLatin1String("f_coming_soon")) ||
        att.endsWith(QLatin1String("d_reconciliationdate"))) {
        return KIcon("dialog-ok");
    }
    if (att.endsWith(QLatin1String("t_close"))) {
        return KIcon("window-close");
    }
    if (att.endsWith(QLatin1String("t_categorycondition")) ||
        att.endsWith(QLatin1String("t_category")) ||
        att.endsWith(QLatin1String("t_realcategory"))) {
        return KIcon("skrooge_category");
    }
    if (att.endsWith(QLatin1String("t_symbol"))) {
        return KIcon("view-currency-list");
    }
    if (att.endsWith(QLatin1String("t_typeexpensenls"))) {
        return KIcon("skrooge_type");
    }
    if (att.endsWith(QLatin1String("t_typenls"))) {
        if (att.contains("v_unit")) {
            return KIcon("view-stock-account");
        }
        if (att.contains("v_account")) {
            return KIcon("view-credit-card-account");
        }
    }
    if (att.endsWith(QLatin1String("t_unit")) ||
        att.endsWith(QLatin1String("t_unittype"))) {
        return KIcon("view-currency-list");
    }
    if (att.endsWith(QLatin1String("f_value")) ||
        att.endsWith(QLatin1String("f_currentamount")) ||
        att.endsWith(QLatin1String("f_todayamount")) ||
        att.endsWith(QLatin1String("f_sumcurrentamount")) ||
        att.endsWith(QLatin1String("quantity")) ||
        att.endsWith(QLatin1String("f_realcurrentamount"))) {
        return KIcon("skrooge_type");
    }
    if (att.endsWith(QLatin1String("_expense"))) {
        return KIcon("list-remove");
    }
    if (att.endsWith(QLatin1String("_income")) ||
        att.endsWith(QLatin1String("f_annual_interest")) ||
        att.endsWith(QLatin1String("f_accrued_interest"))) {
        return KIcon("list-add");
    }
    if (att.endsWith(QLatin1String("t_description"))) {
        return KIcon("edit-find");
    }
    if (att.endsWith(QLatin1String("t_action_description"))) {
        return KIcon("system-run");
    }
    if (att.endsWith(QLatin1String("t_imported"))) {
        return KIcon("utilities-file-archiver");
    }
    if (att.endsWith(QLatin1String("t_refund")) ||
        att.endsWith(QLatin1String("t_realrefund"))) {
        return KIcon("skrooge_tracker");
    }
    if (att.endsWith(QLatin1String("t_mode"))) {
        return KIcon("skrooge_credit_card");
    }
    if (att.endsWith(QLatin1String("t_account")) ||
        att.endsWith(QLatin1String("t_toaccount")) ||
        att.endsWith(QLatin1String("t_accounttype"))) {
        return KIcon("kwalletmanager");
    }
    if (att.endsWith(QLatin1String("t_payee"))) {
        return KIcon("skrooge_payee");
    }
    if (att.endsWith(QLatin1String("t_comment")) ||
        att.endsWith(QLatin1String("t_realcomment"))) {
        return KIcon("draw-freehand");
    }
    if (att.endsWith(QLatin1String("t_warn")) ||
        att.endsWith(QLatin1String("i_warn_days"))) {
        return KIcon("dialog-warning");
    }
    if (att.endsWith(QLatin1String("t_name"))) {
        if (att.contains("v_account")) {
            return KIcon("kwalletmanager");
        }
        if (att.contains("v_category")) {
            return KIcon("skrooge_category");
        }
        if (att.contains("v_refund")) {
            return KIcon("skrooge_tracker");
        }
        if (att.contains("v_unit")) {
            return KIcon("view-currency-list");
        }
        if (att.contains("v_payee")) {
            return KIcon("skrooge_payee");
        }
    }
    if (att.endsWith(QLatin1String("f_rate"))) {
        return KIcon("skrooge_more");
    }
    if (att.endsWith(QLatin1String("t_internet_code")) || att.endsWith(QLatin1String("t_source")) || att.endsWith(QLatin1String("d_maxdate"))) {
        return KIcon("download");
    }
    if (att.contains(QLatin1String(".d_")) || att.startsWith(QLatin1String("d_"))) {
        return KIcon("view-calendar");
    }
    if (att.endsWith(QLatin1String("i_year")) || att.endsWith(QLatin1String("i_month")) || att.endsWith(QLatin1String("t_period"))) {
        return KIcon("view-calendar");
    }
    if (att.endsWith(QLatin1String("f_delta"))) {
        return KIcon("security-high");
    }
    if (att.endsWith(QLatin1String("f_deltabeforetransfer"))) {
        return KIcon("security-medium");
    }
    if (att.endsWith(QLatin1String("f_budgeted")) || att.endsWith(QLatin1String("f_budgeted_modified"))) {
        return KIcon("view-income-categories");
    }
    if (att.endsWith(QLatin1String("t_rules"))) {
        return KIcon("system-run");
    }
    if (att.endsWith(QLatin1String("t_whennls"))) {
        return KIcon("view-calendar");
    }
    if (att.endsWith(QLatin1String("t_whatnls"))) {
        return KIcon("skrooge_type");
    }
    if (att.endsWith(QLatin1String("t_rulenls"))) {
        return KIcon("view-income-categories");
    }
    if (att.endsWith(QLatin1String("t_bank"))) {
        return KIcon("view-bank");
    }
    if (att.endsWith(QLatin1String("t_transfer"))) {
        return KIcon("view-financial-transfer");
    }
    if (att.endsWith(QLatin1String("i_number"))) {
        return KIcon("dialog-information");
    }
    return SKGDocument::getIcon(iString);
}

QString SKGDocumentBank::getDisplay(const QString& iString) const
{
    QString output = iString.toLower();

    // Internationallization
    if (output.endsWith(QLatin1String("account.t_name")) ||
        output.endsWith(QLatin1String("t_account"))) {
        return i18nc("Noun, an account as in a bank account", "Account");
    }
    if (output.endsWith(QLatin1String("t_accounttype"))) {
        return i18nc("Noun, an account as in a bank account", "Account's type");
    }
    if (output.endsWith(QLatin1String("t_operationname"))) {
        return i18nc("Noun, a financial operation", "Operation");
    }
    if (output.endsWith(QLatin1String("t_name"))) {
        return i18nc("Noun, the name of an item", "Name");
    }
    if (output.endsWith(QLatin1String("account.f_value")) ||
        output.endsWith(QLatin1String("f_balance"))) {
        return i18nc("Noun, as in commercial balance", "Balance");
    }
    if (output.endsWith(QLatin1String("f_balance_entered"))) {
        return i18nc("Noun, as in commercial balance", "Balance entered");
    }
    if (output.endsWith(QLatin1String("f_value"))) {
        return i18nc("Name, the numerical amount of a financial operation", "Amount");
    }
    if (output.endsWith(QLatin1String("f_currentamount")) ||
        output.endsWith(QLatin1String("f_realcurrentamount"))) {
        return i18nc("Name, the numerical amount of a financial operation", "Amount");
    }
    if (output.endsWith(QLatin1String("f_todayamount"))) {
        return i18nc("Name, the numerical amount of a financial operation", "Today amount");
    }
    if (output.endsWith(QLatin1String("f_currentamount_income")) ||
        output.endsWith(QLatin1String("f_realcurrentamount_income"))) {
        return i18nc("Noun, financial operations with a positive amount", "Income");
    }
    if (output.endsWith(QLatin1String("f_currentamount_expense")) ||
        output.endsWith(QLatin1String("f_realcurrentamount_expense"))) {
        return i18nc("Noun, financial operations with a negative amount", "Expenditure");
    }
    if (output.endsWith(QLatin1String("f_quantity_income")) ||
        output.endsWith(QLatin1String("f_realquantity_income"))) {
        return i18nc("Noun",  "Income entered");
    }
    if (output.endsWith(QLatin1String("f_quantity_expense")) ||
        output.endsWith(QLatin1String("f_realquantity_expense"))) {
        return i18nc("Noun",  "Expenditure entered");
    }
    if (output.endsWith(QLatin1String("f_quantityowned"))) {
        return i18nc("Noun",  "Quantity owned");
    }
    if (output.endsWith(QLatin1String("f_amountowned"))) {
        return i18nc("Noun",  "Amount owned");
    }
    if (output.endsWith(QLatin1String("quantity"))) {
        return i18nc("Noun",  "Amount entered");
    }
    if (output.endsWith(QLatin1String("account.t_number"))) {
        return i18nc("Noun",  "Account number");
    }
    if (output.endsWith(QLatin1String("t_number")) ||
        output.endsWith(QLatin1String("i_number"))) {
        return i18nc("Noun, a number identifying an item", "Number");
    }
    if (output.endsWith(QLatin1String("t_bank_number"))) {
        return i18nc("Noun",  "Bank number");
    }
    if (output.endsWith(QLatin1String("t_agency_number"))) {
        return i18nc("Noun",  "Agency number");
    }
    if (output.endsWith(QLatin1String("t_agency_address"))) {
        return i18nc("Noun",  "Agency address");
    }
    if (output.endsWith(QLatin1String("t_address"))) {
        return i18nc("Noun",  "Address");
    }
    if (output.endsWith(QLatin1String("t_payee"))) {
        return i18nc("A person or institution receiving a payment, or paying the operation", "Payee");
    }
    if (output.endsWith(QLatin1String("t_comment"))) {
        return i18nc("Noun, a user comment on an item", "Comment");
    }
    if (output.endsWith(QLatin1String("t_realcomment"))) {
        return i18nc("Noun, a user comment on an item", "Sub comment");
    }
    if (output.endsWith(QLatin1String("t_mode"))) {
        return i18nc("Noun, the mode used for payment of the operation (Credit Card, Cheque, Transfer...)", "Mode");
    }
    if (output.contains("recurrentoperation") && output.endsWith(QLatin1String("d_date"))) {
        return i18nc("Noun",  "Next occurrence");
    }
    if (output.endsWith(QLatin1String("d_date")) ||
        output.endsWith(QLatin1String("d_dateop"))) {
        return i18nc("Noun, the date of an item", "Date");
    }
    if (output.endsWith(QLatin1String("d_createdate"))) {
        return i18nc("Noun, the date of creation of an item", "Creation date");
    }
    if (output.endsWith(QLatin1String("d_dateweek"))) {
        return i18nc("Noun, 7 days", "Week");
    }
    if (output.endsWith(QLatin1String("d_datemonth"))) {
        return i18nc("Noun, the months in a year", "Month");
    }
    if (output.endsWith(QLatin1String("d_datequarter"))) {
        return i18nc("Noun, 3 months", "Quarter");
    }
    if (output.endsWith(QLatin1String("d_datesemester"))) {
        return i18nc("Noun, 6 months", "Semester");
    }
    if (output.endsWith(QLatin1String("d_dateyear"))) {
        return  i18nc("Noun, the years in a century", "Year");
    }
    if (output.endsWith(QLatin1String("d_firstdate"))) {
        return i18nc("Noun, the date of an item", "First date");
    }
    if (output.endsWith(QLatin1String("d_lastdate"))) {
        return i18nc("Noun, the date of an item", "Last date");
    }
    if (output.endsWith(QLatin1String("d_maxdate"))) {
        return i18nc("Noun, the date of the last download", "Download date");
    }
    if (output.endsWith(QLatin1String("d_reconciliationdate"))) {
        return i18nc("Noun, the date of the last reconciliation", "Reconciliation date");
    }
    if (output.endsWith(QLatin1String("t_categorycondition")) ||
        output.endsWith(QLatin1String("t_category")) ||
        output.endsWith(QLatin1String("t_realcategory"))) {
        return i18nc("Noun, the category of an item", "Category");
    }
    if (output.endsWith(QLatin1String("t_bank"))) {
        return i18nc("Noun, a financial institution", "Bank");
    }
    if (output.endsWith(QLatin1String("t_unit"))) {
        return i18nc("Noun, the unit of an operation, usually a currency or a share", "Unit");
    }
    if (output.endsWith(QLatin1String("t_unittype"))) {
        return i18nc("Noun, the unit of an operation, usually a currency or a share", "Unit's type");
    }
    if (output.endsWith(QLatin1String("f_checked"))) {
        return i18nc("Adjective, has an item been checked or not", "Checked");
    }
    if (output.endsWith(QLatin1String("f_coming_soon"))) {
        return i18nc("Adjective, a foreseen value", "To be Checked");
    }
    if (output.endsWith(QLatin1String("t_symbol"))) {
        return i18nc("Noun, ahe unit symbol, something in the line of $, €, £...", "Symbol");
    }
    if (output.endsWith(QLatin1String("t_country"))) {
        return i18nc("Noun, a country in the world (France, China...)", "Country");
    }
    if (output.endsWith(QLatin1String("t_type")) ||
        output.endsWith(QLatin1String("t_typenls"))) {
        return i18nc("Noun, the type of an item", "Type");
    }
    if (output.endsWith(QLatin1String("t_typeexpensenls"))) {
        return i18nc("Noun, the type of an item", "Type");
    }
    if (output.endsWith(QLatin1String("t_internet_code"))) {
        return i18nc("Noun",  "Internet code");
    }
    if (output.endsWith(QLatin1String("i_nboperations"))) {
        return i18nc("Noun",  "Number of operations");
    }
    if (output.endsWith(QLatin1String("t_periodnls"))) {
        return i18nc("Noun, how frequently something occurs", "Periodicity");
    }
    if (output.endsWith(QLatin1String("i_auto_write_days"))) {
        return i18nc("Automatically write something", "Auto write");
    }
    if (output.endsWith(QLatin1String("i_nb_times"))) {
        return i18nc("Noun",  "Nb of occurrences");
    }
    if (output.endsWith(QLatin1String("i_warn_days"))) {
        return i18nc("Verb, warn the user about an event", "Warn");
    }
    if (output.endsWith(QLatin1String("t_close"))) {
        return i18nc("Adjective, a closed item", "Closed");
    }
    if (output.endsWith(QLatin1String("t_bookmarked"))) {
        return i18nc("Adjective, an highlighted item", "Highlighted");
    }
    if (output.endsWith(QLatin1String("t_status"))) {
        return i18nc("Noun, the status of an item", "Status");
    }
    if (output.endsWith(QLatin1String("i_nbrecurrent"))) {
        return i18nc("Adjective, an item scheduled to happen on a regular basis", "Scheduled");
    }
    if (output.endsWith(QLatin1String("i_sumnboperations"))) {
        return i18nc("Noun",  "Number of operations (cumulative)");
    }
    if (output.endsWith(QLatin1String("f_sumcurrentamount"))) {
        return i18nc("Noun",  "Amount (cumulative)");
    }
    if (output.endsWith(QLatin1String("t_description"))) {
        return i18nc("Noun",  "Search description");
    }
    if (output.endsWith(QLatin1String("t_action_description"))) {
        return i18nc("Noun",  "Process description");
    }
    if (output.endsWith(QLatin1String("t_action_type"))) {
        return i18nc("Noun, the type of action", "Action type");
    }
    if (output.endsWith(QLatin1String("t_refund")) ||
        output.endsWith(QLatin1String("t_realrefund"))) {
        return i18nc("Noun, something that is used to track items", "Tracker");
    }
    if (output.endsWith(QLatin1String("t_imported"))) {
        return i18nc("Noun",  "Import status");
    }
    if (output.endsWith(QLatin1String("i_nbdecimal"))) {
        return i18nc("Noun, after the dot",  "Nb decimal");
    }
    if (output.endsWith(QLatin1String("f_rate"))) {
        return i18nc("Noun, for a share",  "Rate");
    }
    if (output.endsWith(QLatin1String("d_valuedate"))) {
        return i18nc("Noun",  "Value date");
    }
    if (output.endsWith(QLatin1String("f_coef"))) {
        return i18nc("Noun",  "Coef");
    }
    if (output.endsWith(QLatin1String("f_annual_interest"))) {
        return i18nc("Noun",  "Annual Interest");
    }
    if (output.endsWith(QLatin1String("f_accrued_interest"))) {
        return i18nc("Noun",  "Accrued Interest");
    }
    if (output.endsWith(QLatin1String("t_income_value_date_mode"))) {
        return i18nc("Noun",  "Value date for credit");
    }
    if (output.endsWith(QLatin1String("t_expenditure_value_date_mode"))) {
        return i18nc("Noun",  "Value date for debit");
    }
    if (output.endsWith(QLatin1String("t_base"))) {
        return i18nc("Noun",  "Base computation");
    }
    if (output.endsWith(QLatin1String("i_year"))) {
        return i18nc("Noun",  "Year");
    }
    if (output.endsWith(QLatin1String("i_month"))) {
        return i18nc("Noun",  "Month");
    }
    if (output.endsWith(QLatin1String("t_period"))) {
        return i18nc("Noun",  "Period");
    }
    if (output.endsWith(QLatin1String("i_order"))) {
        return i18nc("Noun, sort order", "Order");
    }
    if (output.endsWith(QLatin1String("t_whennls"))) {
        return i18nc("Noun", "When");
    }
    if (output.endsWith(QLatin1String("t_whatnls"))) {
        return i18nc("Noun", "What");
    }
    if (output.endsWith(QLatin1String("t_rulenls"))) {
        return i18nc("Noun", "Impacted budget");
    }
    if (output.endsWith(QLatin1String("t_rules"))) {
        return i18nc("Noun", "Rules");
    }
    if (output.endsWith(QLatin1String("f_budgeted"))) {
        return i18nc("Noun", "Entered Budget");
    }
    if (output.endsWith(QLatin1String("f_budgeted_modified"))) {
        return i18nc("Noun", "Corrected budget");
    }
    if (output.endsWith(QLatin1String("f_delta"))) {
        return i18nc("Noun", "Delta after rules");
    }
    if (output.endsWith(QLatin1String("f_deltabeforetransfer"))) {
        return i18nc("Noun", "Delta");
    }
    if (output.endsWith(QLatin1String("t_source"))) {
        return i18nc("Noun", "Download source");
    }
    if (output.endsWith(QLatin1String("t_transfer"))) {
        return i18nc("Noun", "Transfer");
    }
    if (output.endsWith(QLatin1String("t_toaccount"))) {
        return i18nc("Noun, a target account of a transfer", "To account");
    }
    if (output.endsWith(QLatin1String("f_maxamount"))) {
        return i18nc("Noun, a target account of a transfer", "Maximum limit");
    }
    if (output.endsWith(QLatin1String("f_minamount"))) {
        return i18nc("Noun, a target account of a transfer", "Minimum limit");
    }
    if (output.endsWith(QLatin1String("#nothing#"))) {
        return i18nc("Noun, the absence of anything", "-- Nothing --");
    }
    return SKGDocument::getDisplay(iString);
}

QString SKGDocumentBank::getRealAttribute(const QString& iString) const
{
    if (iString.endsWith(QLatin1String("t_BANK"))) {
        return "bank.rd_bank_id.t_name";
    }
    if (iString.endsWith(QLatin1String("t_BANK_NUMBER"))) {
        return "bank.rd_bank_id.t_bank_number";
    }
    return SKGDocument::getRealAttribute(iString);
}

SKGServices::AttributeType SKGDocumentBank::getAttributeType(const QString& iAttributeName) const
{
    SKGServices::AttributeType output = SKGServices::TEXT;
    if (iAttributeName == "t_status" || iAttributeName == "t_imported") {
        return SKGServices::TRISTATE;
    } else if (iAttributeName == "t_close" || iAttributeName == "t_bookmarked"  || iAttributeName == "t_auto_write" ||
               iAttributeName == "t_warn" || iAttributeName == "t_TRANSFER" || iAttributeName == "t_template" ||
               iAttributeName == "t_times" ||
               iAttributeName == "t_absolute" || iAttributeName == "t_category_condition" || iAttributeName == "t_month_condition" || iAttributeName == "t_year_condition" || iAttributeName == "t_including_subcategories") {
        return SKGServices::BOOL;
    } else {
        output = SKGDocument::getAttributeType(iAttributeName);
    }
    return output;
}


QVariantList SKGDocumentBank::getBudget(const QString& iMonth)
{
    SKGTRACEINFUNC(10);
    QVariantList table;
    SKGStringListList listTmp;
    SKGError err = executeSelectSqliteOrder("SELECT t_CATEGORY, f_budgeted, f_CURRENTAMOUNT, f_DELTABEFORETRANSFER, f_budgeted_modified  FROM v_budget "
                                            "where t_PERIOD='" % iMonth % "' ORDER BY t_CATEGORY;",
                                            listTmp);
    int nbval = listTmp.count();
    if (!err && nbval > 1) {
        table.push_back(QVariantList() << "sum" << getDisplay("t_CATEGORY") << getDisplay("f_budgeted_modified") << getDisplay("f_CURRENTAMOUNT") << getDisplay("f_DELTA"));
        double sum1 = 0;
        double sum2 = 0;
        double sum3 = 0;
        double sum4 = 0;
        for (int i = 1; i < nbval; ++i) {  // Ignore header
            double v1 = SKGServices::stringToDouble(listTmp.at(i).at(1));
            double v2 = SKGServices::stringToDouble(listTmp.at(i).at(2));
            double v3 = SKGServices::stringToDouble(listTmp.at(i).at(3));
            double v4 = SKGServices::stringToDouble(listTmp.at(i).at(4));
            table.push_back(QVariantList() << false << listTmp.at(i).at(0) << v1 << v2 << v3 << v4);

            sum1 += v1;
            sum2 += v2;
            sum3 += v3;
            sum4 += v4;
        }
        table.push_back(QVariantList() << true << i18nc("Noun, the numerical total of a sum of values", "Total") << sum1 << sum2 << sum3 << sum4);
    }
    return table;
}

QVariantList SKGDocumentBank::getMainCategories(const QString& iPeriod, int iNb)
{
    SKGTRACEINFUNC(10);
    QVariantList table;
    SKGServices::SKGUnitInfo primary = getPrimaryUnit();

    SKGStringListList listTmp;
    SKGError err = executeSelectSqliteOrder("SELECT t_REALCATEGORY, TOTAL(f_REALCURRENTAMOUNT) FROM v_suboperation_consolidated "
                                            "where t_TRANSFER='N' AND " + SKGServices::getPeriodWhereClause(iPeriod) + " AND t_TYPEEXPENSE='-' "
                                            "group by t_REALCATEGORY order by TOTAL(f_REALCURRENTAMOUNT) LIMIT " % SKGServices::intToString(iNb) % ";",
                                            listTmp);
    int nbval = listTmp.count();
    if (!err && nbval) {
        QVariantList line;
        line << "sum" << getDisplay("t_REALCATEGORY") << iPeriod;
        table.push_back(line);

        for (int i = 1; i < nbval; ++i) {  // Ignore header
            double v = qAbs(SKGServices::stringToDouble(listTmp.at(i).at(1)));
            table.push_back(QVariantList() << false << listTmp.at(i).at(0) << v);
        }
    }
    return table;
}

QStringList SKGDocumentBank::get5MainCategoriesVariationList(const QString& iPeriod, const QString& iPreviousPeriod, bool iOnlyIssues, QStringList* oCategoryList)
{
    SKGTRACEINFUNC(10);
    // Compute input string
    QString inputString = iPeriod % iPreviousPeriod % (iOnlyIssues ? 'Y' : 'N') % (oCategoryList ? 'Y' : 'N');

    // Use cache or not
    QStringList output;
    if (inputString == m_5mainVariations_inputs) {
        // Yes
        output = m_5mainVariations_cache;
        if (oCategoryList) {
            *oCategoryList = m_5mainVariationsCat_cache;
        }
    }
    m_5mainVariations_inputs = inputString;

    if (output.isEmpty()) {
        SKGServices::SKGUnitInfo primary = getPrimaryUnit();

        SKGStringListList listTmp;
        SKGError err = executeSelectSqliteOrder("select *, 100*(A2-A1)/ABS(A1) as 'V' from "
                                                "(SELECT t_REALCATEGORY as 'C1', TOTAL(f_REALCURRENTAMOUNT) as 'A1' FROM v_suboperation_consolidated where "
                                                "t_TRANSFER='N' AND " + SKGServices::getPeriodWhereClause(iPreviousPeriod) + " AND t_TYPEEXPENSE='-' group by t_REALCATEGORY) A,"
                                                "(SELECT t_REALCATEGORY as 'C2', TOTAL(f_REALCURRENTAMOUNT) as 'A2' FROM v_suboperation_consolidated where "
                                                "t_TRANSFER='N' AND " + SKGServices::getPeriodWhereClause(iPeriod) + " AND t_TYPEEXPENSE='-' group by t_REALCATEGORY) B "
                                                "WHERE A.C1=B.C2 AND ABS(A2-A1)/ABS(A1)>0.1 ORDER BY ABS(A2-A1) DESC LIMIT 5;",
                                                listTmp);
        IFOK(err) {
            // Clear the list
            m_5mainVariations_cache.clear();
            m_5mainVariationsCat_cache.clear();

            // Fill list
            int nbval = listTmp.count();
            for (int i = 1; i < nbval; ++i) {  // Ignore header
                QString m = listTmp.at(i).at(1);
                /*Example of sentences:
                  Expenses in category "Food > Grocery" in November decreased by 14% for a total  of 220,48€.
                  Expenses in category "Food" (no subcategory) in November increased by 24% for a total of 70,20€.
                  Expenses in category "Automotive > Fuel" in November increased by 24% for a total of 122,48€.
                  Expenses in category "Misc" in November decreased by 30% for a total of 36,52€.
                  This month, you spent 75,00€ in Category "Bills > Subscriptions". No expense in that category was found in previous month
                  Expenses with mode "withdrawal" reprensented 60,00€ of your expenses in current month*/
                QString c1 = listTmp.at(i).at(0);
                double a1 = SKGServices::stringToDouble(listTmp.at(i).at(1));
                double a2 = SKGServices::stringToDouble(listTmp.at(i).at(3));
                double v = SKGServices::stringToDouble(listTmp.at(i).at(4));

                QString a2f = formatMoney(qAbs(a2), primary);
                if (a1 < 0 && a2 < 0) {
                    QString vf = formatPercentage(qAbs(v), v < 0);
                    if (v < 0) {
                        m_5mainVariations_cache.push_back(i18n("Expenses in category <b>'%1'</b> increased by <b>%2</b> for a total of <b>%3</b>.", c1, vf, a2f));
                        m_5mainVariationsCat_cache.push_back(c1);
                    } else {
                        if (!iOnlyIssues) {
                            m_5mainVariations_cache.push_back(i18n("Expenses in category <b>'%1'</b> decreased by <b>%2</b> for a total of <b>%3</b>.", c1, vf, a2f));
                            m_5mainVariationsCat_cache.push_back(c1);
                        }
                    }
                } else if (a1 > 0 && a2 > 0) {
                    QString vf = formatPercentage(qAbs(v));
                    if (v > 0) {
                        if (!iOnlyIssues) {
                            m_5mainVariations_cache.push_back(i18n("Incomes in category <b>'%1'</b> increased by <b>%2</b> for a total of <b>%3</b>.", c1, vf, a2f));
                            m_5mainVariationsCat_cache.push_back(c1);
                        }
                    } else {
                        m_5mainVariations_cache.push_back(i18n("Incomes in category <b>'%1'</b> decreased by <b>%2</b> for a total of <b>%3</b>.", c1, vf, a2f));
                        m_5mainVariationsCat_cache.push_back(c1);
                    }
                }
            }
        }
        output = m_5mainVariations_cache;
        if (oCategoryList) {
            *oCategoryList = m_5mainVariationsCat_cache;
        }
    }
    return output;
}

SKGReport* SKGDocumentBank::getReport()
{
    return new SKGReportBank(this);
}

#include "skgdocumentbank.moc"
