import csv
import os.path
import traceback
import numpy as np
import datetime as dt
from datetime import datetime, timedelta
from dateutil.relativedelta import *
import shutil
import sys
import json
import pathlib
import time
import zipfile
import rappmysql
import argparse
import textwrap
import mysql.connector as mysql
from rappmysql.mysqlquerys import connect
from rappmysql.mysqlquerys import mysql_rm

np.set_printoptions(linewidth=250)
__version__ = 'V5'

app_chelt_tables = {'chelt_plan': 'user_id', 'yearly_plan': 'user_id', 'yearly_all': 'user_id'}
app_income_tables = {'income': 'user_id'}
app_real_expenses = {'banca': 'id_users',
                     'knowntrans': 'id_users',
                     'imported_csv': 'id_users',
                     'deubnk': 'id_users',
                     'n26': 'id_users',
                     'sskm': 'id_users',
                     'plan_vs_real': 'id_users',
                     }
app_chelt_gui = ['chelt_plan.ui', 'filterWindow.ui']

tables_app_dict = {'planned_expenses_app': {'users': 'id',
                                            'user_apps': 'id_users',
                                            'chelt_plan': 'id_users',
                                            'yearly_plan': 'id_users'},
                   'real_expenses_app': {'users': 'id',
                                         'user_apps': 'id_users',
                                         'chelt_plan': 'id_users',
                                         'yearly_plan': 'id_users',
                                         'banca': 'id_users',
                                         'knowntrans': 'id_users',
                                         'income': 'id_users',
                                         'deubnk': 'id_users',
                                         'n26': 'id_users',
                                         'sskm': 'id_users',
                                         'plan_vs_real': 'id_users',
                                         'imported_csv': 'id_users',
                                         }
                   }
sskm_tabHeadDict = {'Auftragskonto': 'Auftragskonto',
                    'Buchungstag': 'Buchungstag',
                    'Valutadatum': 'Valutadatum',
                    'Buchungstext': 'Buchungstext',
                    'Verwendungszweck': 'Verwendungszweck',
                    'Glaeubiger ID': 'Glaeubiger',
                    'Mandatsreferenz': 'Mandatsreferenz',
                    'Kundenreferenz (End-to-End)': 'Kundenreferenz',
                    'Sammlerreferenz': 'Sammlerreferenz',
                    'Lastschrift Ursprungsbetrag': 'Lastschrift',
                    'Auslagenersatz Ruecklastschrift': 'Auslagenersatz',
                    'Beguenstigter/Zahlungspflichtiger': 'Beguenstigter',
                    'Kontonummer/IBAN': 'IBAN',
                    'BIC (SWIFT-Code)': 'BIC',
                    'Betrag': 'Betrag',
                    'Waehrung': 'Waehrung',
                    'Info': 'Info'}
n26_tabHeadDict0 = {'Date': 'Buchungstag',
                    # 'Value Date': 'ValueDate',
                    'Payee': 'Beguenstigter',
                    'Account number': 'IBAN',
                    'Transaction type': 'Type',
                    'Payment reference': 'PaymentReference',
                    # 'Account Name': 'AccountName',
                    'Amount (EUR)': 'Amount',
                    'Amount (Foreign Currency)': 'OriginalAmount',
                    'Type Foreign Currency': 'OriginalCurrency',
                    'Exchange Rate': 'ExchangeRate'
                    }
n26_tabHeadDict1 = {'Booking Date': 'Buchungstag',
                    'Value Date': 'ValueDate',
                    'Partner Name': 'Beguenstigter',
                    'Partner Iban': 'IBAN',
                    'Type': 'Type',
                    'Payment Reference': 'PaymentReference',
                    'Account Name': 'AccountName',
                    'Amount (EUR)': 'Amount',
                    'Original Amount': 'OriginalAmount',
                    'Original Currency': 'OriginalCurrency',
                    'Exchange Rate': 'ExchangeRate'
                    }
db_tabHeadDict0 = {'Booking date': 'Buchungstag',
                   'Value date': 'Valuedate',
                   'Transaction Type': 'TransactionType',
                   'Beneficiary / Originator': 'Beguenstigter',
                   'Payment Details': 'Verwendungszweck',
                   'IBAN': 'IBAN',
                   'BIC': 'BIC',
                   'Customer Reference': 'CustomerReference',
                   'Mandate Reference': 'Mandatsreferenz',
                   'Creditor ID': 'CreditorID',
                   'Compensation amount': 'Compensationamount',
                   'Original Amount': 'OriginalAmount',
                   'Ultimate creditor': 'Ultimatecreditor',
                   # 'Ultimate debtor': 'Ultimatedebtor',
                   'Number of transactions': 'Numberoftransactions',
                   'Number of cheques': 'Numberofcheques',
                   'Debit': 'Debit',
                   'Credit': 'Credit',
                   'Currency': 'Currency'
                   }
db_tabHeadDict1 = {'Buchungstag': 'Buchungstag',
                   'Wert': 'Valuedate',
                   'Umsatzart': 'TransactionType',
                   'Begünstigter / Auftraggeber': 'Beguenstigter',
                   'Verwendungszweck': 'Verwendungszweck',
                   'IBAN': 'IBAN',
                   'BIC': 'BIC',
                   'Kundenreferenz': 'CustomerReference',
                   'Mandatsreferenz ': 'Mandatsreferenz',
                   'Gläubiger ID': 'CreditorID',
                   'Fremde Gebühren': 'Compensationamount',
                   'Betrag': 'OriginalAmount',
                   'Abweichender Empfänger': 'Ultimatecreditor',
                   'Abweichender Auftraggeber': 'Ultimatedebtor',
                   'Anzahl der Aufträge': 'Numberoftransactions',
                   'Anzahl der Schecks': 'Numberofcheques',
                   'Soll': 'Debit',
                   'Haben': 'Credit',
                   'Währung': 'Currency'
                   }
db_tabHeadDict2 = {'Booking date': 'Buchungstag',
                   'Value date': 'Valuedate',
                   'Transaction Type': 'TransactionType',
                   'Beneficiary / Originator': 'Beguenstigter',
                   'Payment Details': 'Verwendungszweck',
                   'IBAN / Account Number': 'IBAN',
                   # 'IBAN / Account Number': 'IBAN',
                   'BIC': 'BIC',
                   'Customer Reference': 'CustomerReference',
                   'Mandate Reference': 'Mandatsreferenz',
                   'Creditor ID': 'CreditorID',
                   'Compensation amount': 'Compensationamount',
                   'Original Amount': 'OriginalAmount',
                   'Ultimate creditor': 'Ultimatecreditor',
                   # 'Ultimate debtor': 'Ultimatedebtor',
                   'Number of transactions': 'Numberoftransactions',
                   'Number of cheques': 'Numberofcheques',
                   'Debit': 'Debit',
                   'Credit': 'Credit',
                   'Currency': 'Currency'
                   }
db_tabHeadDict3 = {'Booking date': 'Buchungstag',
                   'Value date': 'Valuedate',
                   'Transaction Type': 'TransactionType',
                   'Beneficiary / Originator': 'Beguenstigter',
                   'Payment Details': 'Verwendungszweck',
                   'IBAN': 'IBAN',
                   'BIC': 'BIC',
                   'Customer Reference': 'CustomerReference',
                   'Mandate Reference': 'Mandatsreferenz',
                   'Creditor ID': 'CreditorID',
                   'Compensation amount': 'Compensationamount',
                   'Original Amount': 'OriginalAmount',
                   'Ultimate creditor': 'Ultimatecreditor',
                   'Ultimate debtor': 'Ultimatedebtor',
                   'Number of transactions': 'Numberoftransactions',
                   'Number of cheques': 'Numberofcheques',
                   'Debit': 'Debit',
                   'Credit': 'Credit',
                   'Currency': 'Currency'
                   }

plan_vs_real_tabHeadDict = {'sskm': {'Buchungstag': 'Buchungstag',
                                     'myconto': 'myconto',
                                     'Betrag': 'Betrag',
                                     'PaymentReference': 'Verwendungszweck',
                                     'PartnerName': 'Beguenstigter'},
                            'n26': {'Buchungstag': 'Buchungstag',
                                    'myconto': 'myconto',
                                    'Betrag': 'Amount',
                                    'PaymentReference': 'PaymentReference',
                                    'PartnerName': 'Beguenstigter'},
                            'deubnk': {'Buchungstag': 'Buchungstag',
                                       'myconto': 'myconto',
                                       'Betrag': 'Debit',
                                       'PaymentReference': 'Verwendungszweck',
                                       'PartnerName': 'Beguenstigter'},
                            }

bank_tabHeadDict = {'Stadtsparkasse München': [sskm_tabHeadDict],
                    'N26': [n26_tabHeadDict0, n26_tabHeadDict1],
                    'DeutscheBank': [db_tabHeadDict0,
                                     db_tabHeadDict1,
                                     db_tabHeadDict2,
                                     db_tabHeadDict3],
                    }

bank_sql_table = {'Stadtsparkasse München': 'sskm',
                  'N26': 'n26',
                  'DeutscheBank': 'deubnk',
                  }


def convert_months(month):
    if isinstance(month, int):
        x = datetime(2024, month, 1)
        x = x.strftime("%B")
        return x
    elif isinstance(month, str):
        x = datetime.strptime(month, '%B')
        return x.month


def calculate_last_day_of_month(mnth, year):
    if mnth < 12:
        # lastDayOfMonth = datetime(datetime.now().year, mnth + 1, 1) - timedelta(days=1)
        lastDayOfMonth = datetime(year, mnth + 1, 1) - timedelta(days=1)
        lastDayOfMonth = lastDayOfMonth.day
    elif mnth == 12:
        lastDayOfMonth = 31
    return lastDayOfMonth


def calculate_today_plus_x_days(x_days):
    result = datetime(datetime.now().year, datetime.now().month, datetime.now().day) + timedelta(days=int(x_days))
    return result


def default_interval():
    # #print('Module: {}, Class: {}, Def: {}'.format(__name__, __class__, sys._getframe().f_code.co_name))
    # #print('Caller : ', sys._getframe().f_back.f_code.co_name)
    startDate = datetime(datetime.now().year, datetime.now().month, datetime.now().day)
    if datetime.now().month != 12:
        mnth = datetime.now().month + 1
        lastDayOfMonth = datetime(datetime.now().year, mnth, 1) - timedelta(days=1)
    else:
        lastDayOfMonth = datetime(datetime.now().year + 1, 1, 1) - timedelta(days=1)

    return startDate, lastDayOfMonth


def get_monthly_interval(month: str, year):
    # #print('Module: {}, Class: {}, Def: {}'.format(__name__, __class__, sys._getframe().f_code.co_name))
    mnth = datetime.strptime(month, "%B").month
    startDate = datetime(year, mnth, 1)

    if mnth != 12:
        lastDayOfMonth = datetime(year, mnth + 1, 1) - timedelta(days=1)
    else:
        lastDayOfMonth = datetime(year + 1, 1, 1) - timedelta(days=1)

    return startDate.date(), lastDayOfMonth.date()


def convert_to_display_table(tableHead, table, displayTableHead):
    # #print('tableHead', tableHead)
    # #print('displayTableHead', displayTableHead)

    newTableData = np.empty([table.shape[0], len(displayTableHead)], dtype=object)
    for i, col in enumerate(displayTableHead):
        # print(col)
        indxCol = tableHead.index(col)
        newTableData[:, i] = table[:, indxCol]
    return displayTableHead, newTableData


class DB_Connection:
    def __init__(self, ini_masina):
        if isinstance(ini_masina, dict):
            self.credentials = ini_masina
        else:
            self.conf = connect.Config(ini_masina)
            self.credentials = self.conf.credentials

        if not isinstance(self.credentials, dict):
            raise RuntimeError('Credentials not dict')
        self.chelt_db = self.sql_rm.DataBase(self.credentials)
        if not self.chelt_db.is_connected:
            raise RuntimeError('Could not connect to database')
        # print('Connected to database:{}'.format(self.credentials['database']), self.chelt_db.is_connected)
        self.refresh_db()

    def refresh_db(self):
        # print(100*'refresh_db')
        self.chelt_plan = self.sql_rm.Table(self.conf.credentials, 'chelt_plan')
        self.yearly_plan = self.sql_rm.Table(self.conf.credentials, 'yearly_plan')
        self.yearly_all = self.sql_rm.Table(self.conf.credentials, 'yearly_all')
        self.myAccountsTable = None
        if 'banca' in self.chelt_db.allAvailableTablesInDatabase:
            self.myAccountsTable = self.sql_rm.Table(self.conf.credentials, 'banca')
            self.myContos = self.myAccountsTable.returnColumn('name')
        self.income_table = None
        if 'income' in self.chelt_db.allAvailableTablesInDatabase:
            self.income_table = self.sql_rm.Table(self.conf.credentials, 'income')

        self.imported_csv = self.sql_rm.Table(self.conf.credentials, 'imported_csv')
        self.plan_vs_real = self.sql_rm.Table(self.conf.credentials, 'plan_vs_real')
        self.knowntrans = self.sql_rm.Table(self.conf.credentials, 'knowntrans')
        self.sskm = self.sql_rm.Table(self.conf.credentials, 'sskm')
        self.deubnk = self.sql_rm.Table(self.conf.credentials, 'deubnk')
        self.n26 = self.sql_rm.Table(self.conf.credentials, 'n26')

    @property
    def sql_rm(self):
        if self.conf.db_type == 'mysql':
            sql_rm = mysql_rm
        return sql_rm

    def close_connection(self):
        self.chelt_db.db.close()
        # self.chelt_plan.close()
        # self.yearly_plan.close()


class CheckCheltRequiredFiles:
    def __init__(self, chelt_db, *tables):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                           sys._getframe().f_back.f_code.co_name))
        self.caller_class = sys._getframe(1).f_locals.get('self', None).__class__.__name__
        self.chelt_db = chelt_db
        path2GUI = pathlib.Path(__file__)
        self.path2GUI = path2GUI.resolve(path2GUI).parent / 'GUI'
        self.pth2SQLtables = os.path.join(os.path.dirname(__file__), 'static', 'sql')
        self.check_chelt_sql_gui_files()
        self.check_tabels_in_chelt_db()
        self.check_if_db_table_same_as_sql_file(*tables)

    def check_chelt_sql_gui_files(self, ):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        for table in app_chelt_tables.keys():
            sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table))
            # #print('##sql_table_template##', sql_file)
            if not os.path.exists(sql_file):
                raise FileNotFoundError('{}'.format(sql_file))

        # if self.has_cheltuieli_real:
        #     for table in app_real_expenses.keys():
        #         sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table))
        #         #print('##sql_table_template##', sql_file)
        #         if not os.path.exists(sql_file):
        #             raise FileNotFoundError('{}'.format(sql_file))

        for gui in app_chelt_gui:
            sql_file = os.path.join(self.path2GUI, gui)
            # #print('##gui_file##', sql_file)
            if not os.path.exists(sql_file):
                raise FileNotFoundError('{}'.format(sql_file))

    def check_tabels_in_chelt_db(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.caller_class == 'CheltuieliPlanificate' or self.caller_class == 'CheltApp':
            for table in app_chelt_tables.keys():
                # #print('##table##', table)
                sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table))
                if table not in self.chelt_db.allAvailableTablesInDatabase:
                    if __name__ == '__main__':
                        txt = 'Table {} not in database...should I create it?\nY/N\n'.format(table)
                        user_input = input(txt)
                        if user_input == 'Y':
                            # print('Creating {}'.format(table))
                            self.chelt_db.createTableFromFile(sql_file, table)
                    else:
                        txt = 'Table {} not in database...creating it?'.format(table)
                        # print(txt)
                        self.chelt_db.createTableFromFile(sql_file, table)
        if self.caller_class == 'CheltuieliReale':
            for table in app_real_expenses.keys():
                # #print('##table##', table)
                sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table))
                if table not in self.chelt_db.allAvailableTablesInDatabase:
                    if __name__ == '__main__':
                        txt = 'Table {} not in database...should I create it?\nY/N\n'.format(table)
                        user_input = input(txt)
                        if user_input == 'Y':
                            # print('Creating {}'.format(table))
                            self.chelt_db.createTableFromFile(sql_file, table)
                    else:
                        txt = 'Table {} not in database...creating it?'.format(table)
                        # print(txt)
                        self.chelt_db.createTableFromFile(sql_file, table)
        if self.caller_class == 'Income':
            for table in app_income_tables.keys():
                # #print('##table##', table)
                sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table))
                if table not in self.chelt_db.allAvailableTablesInDatabase:
                    if __name__ == '__main__':
                        txt = 'Table {} not in database...should I create it?\nY/N\n'.format(table)
                        user_input = input(txt)
                        if user_input == 'Y':
                            # print('Creating {}'.format(table))
                            self.chelt_db.createTableFromFile(sql_file, table)
                    else:
                        txt = 'Table {} not in database...creating it?'.format(table)
                        # print(txt)
                        self.chelt_db.createTableFromFile(sql_file, table)

    def check_if_db_table_same_as_sql_file(self, *tables):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                           sys._getframe().f_back.f_code.co_name))
        for table in tables:
            if table is not None:
                # print('-----', table.tableName)
                sql_file = os.path.join(self.pth2SQLtables, '{}_template.sql'.format(table.tableName))
                same = table.compare_sql_file_to_sql_table(sql_file)
            # if same is not True:
            #     #print(same)


class CheltApp:
    def __init__(self, user_id, chelt_db, chelt_plan, yearly_plan, myAccountsTable=None, income_table=None,
                 imported_csv=None):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        self.id = user_id
        try:
            self.chelt_db = chelt_db
            self.chelt_plan = chelt_plan
            self.yearly_plan = yearly_plan
            self.myAccountsTable = myAccountsTable
            self.income_table = income_table
            self.imported_csv = imported_csv
            # CheckCheltRequiredFiles(self.chelt_db, self.chelt_plan, self.yearly_plan)
        except:
            # print('Could not connect to Tables')
            raise RuntimeError('Could not connect to Tables')

    @property
    def has_cheltuieli_planned(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        all_ids = list(set(self.chelt_plan.returnColumn('id_users')))
        has_cheltuieli_planned = self.id in all_ids
        return has_cheltuieli_planned

    @property
    def has_cheltuieli_real(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('KKKKKKKKK')
        # matches = [('id_users', self.id), ('app_name', 'cheltuieli')]
        # cells = self.user_apps_table.returnCellsWhere('modules', matches)
        # if cells:
        #     cell = cells[0]
        #
        #     if 'real' in cell:
        #         # #print('BINGOOOOO')
        #         # self.chelt_app_reale_checkup_tables()
        #         return True
        if not self.myAccountsTable:
            return False
        else:
            all_ids = list(set(self.myAccountsTable.returnColumn('id_users')))
            has_cheltuieli_real = self.id in all_ids
            return has_cheltuieli_real

    @property
    def has_planned_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('KKKKKKKKK')
        # matches = [('id_users', self.id), ('app_name', 'cheltuieli')]
        # cells = self.user_apps_table.returnCellsWhere('modules', matches)
        # if cells:
        #     cell = cells[0]
        #
        #     if 'real' in cell:
        #         # #print('BINGOOOOO')
        #         # self.chelt_app_reale_checkup_tables()
        #         return True
        if not self.income_table:
            return False
        else:
            all_ids = list(set(self.income_table.returnColumn('id_users')))
            has_cheltuieli_income = self.id in all_ids
            return has_cheltuieli_income

    def export_chelt_plan_sql(self, export_files=False):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        tables = {}
        tables4export = ['chelt_plan']
        for tab in tables4export:
            tables[tab] = {'id_users': self.id}
        tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
        output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                  '{:09d}'.format(self.id), 'chelt_plan',
                                  '{}_{:09d}'.format(tim, self.id))
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        if export_files:
            sql_query = self.chelt_db.return_sql_text(tables, export_files=output_dir)
        else:
            sql_query = self.chelt_db.return_sql_text(tables)

        output_sql_file = os.path.join(output_dir, '{}_{:09d}.sql'.format(tim, self.id))
        FILE = open(output_sql_file, "w", encoding="utf-8")
        FILE.writelines(sql_query)
        FILE.close()
        #####
        output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
        zip_file = self.zip_profile_files(output_dir, output_zip)
        if os.path.exists(zip_file):
            shutil.rmtree(output_dir)
        # print('finished backup', output_zip)
        return output_sql_file

    def export_income_plan_sql(self, export_files=False):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        tables = {}
        for tab in app_income_tables:
            tables[tab] = {'id_users': self.id}
        tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
        output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                  '{:09d}'.format(self.id), 'income_plan',
                                  '{}_{:09d}'.format(tim, self.id))
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        if export_files:
            sql_query = self.chelt_db.return_sql_text(tables, export_files=output_dir)
        else:
            sql_query = self.chelt_db.return_sql_text(tables)

        output_sql_file = os.path.join(output_dir, '{}_{:09d}.sql'.format(tim, self.id))
        FILE = open(output_sql_file, "w", encoding="utf-8")
        FILE.writelines(sql_query)
        FILE.close()
        #####
        output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
        zip_file = self.zip_profile_files(output_dir, output_zip)
        if os.path.exists(zip_file):
            shutil.rmtree(output_dir)
        # print('finished backup', output_zip)
        return output_sql_file

    # def export_real_chelt_sql(self, export_files=False):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     tables = {}
    #     for tab in app_income_tables:
    #         tables[tab] = {'id_users': self.id}
    #     tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
    #     output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
    #                               '{:09d}'.format(self.id), 'real_expenses',
    #                               '{}_{:09d}'.format(tim, self.id))
    #     if not os.path.exists(output_dir):
    #         os.makedirs(output_dir)
    #
    #     if export_files:
    #         sql_query = self.chelt_db.return_sql_text(tables, export_files=output_dir)
    #     else:
    #         sql_query = self.chelt_db.return_sql_text(tables)
    #
    #     output_sql_file = os.path.join(output_dir, '{}_{:09d}.sql'.format(tim, self.id))
    #     FILE = open(output_sql_file, "w", encoding="utf-8")
    #     FILE.writelines(sql_query)
    #     FILE.close()
    #     #####
    #     output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
    #     zip_file = self.zip_profile_files(output_dir, output_zip)
    #     if os.path.exists(zip_file):
    #         shutil.rmtree(output_dir)
    #     # print('finished backup', output_zip)
    #     return output_sql_file

    def zip_profile_files(self, src_dir, output_file):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        relroot = os.path.abspath(os.path.join(src_dir, os.pardir))
        with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zip:
            for root, dirs, files in os.walk(src_dir):
                # add directory (needed for empty dirs)
                zip.write(root, os.path.relpath(root, relroot))
                for file in files:
                    filename = os.path.join(root, file)
                    if os.path.isfile(filename):  # regular files only
                        arcname = os.path.join(os.path.relpath(root, relroot), file)
                        zip.write(filename, arcname)
        return output_file

    def export_profile(self, output_dir=None, export_files=False):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # chelt_plan_ident = {'id_users': self.id}
        # yearly_plan_ident = {'id_users': self.id}
        # tables = {'chelt_plan': chelt_plan_ident,
        #           'yearly_plan': yearly_plan_ident}
        # #print(tables)
        tables = {}
        for tab in app_chelt_tables:
            tables[tab] = {'id_users': self.id}
        for tab in app_real_expenses:
            tables[tab] = {'id_users': self.id}
        # #print(25*'+')
        # #print(#print(tables))
        # return
        tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
        if not output_dir:
            output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                      '{:09d}'.format(self.id),
                                      '{}_{:09d}'.format(tim, self.id))
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        if export_files:
            sql_query = self.chelt_db.return_sql_text(tables, export_files=output_dir)
        else:
            sql_query = self.chelt_db.return_sql_text(tables)

        output_sql_file = os.path.join(output_dir, '{}_{:09d}.sql'.format(tim, self.id))
        FILE = open(output_sql_file, "w", encoding="utf-8")
        FILE.writelines(sql_query)
        FILE.close()
        #####
        output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
        zip_file = self.zip_profile_files(output_dir, output_zip)
        if os.path.exists(zip_file):
            shutil.rmtree(output_dir)
        # print('finished backup', output_zip)
        return output_sql_file

    def import_profile(self, zip_file, import_files=False):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        output_dir, file = os.path.split(zip_file)
        src_dir = self.unzip_profile_files(zip_file, output_dir)
        src_dir = os.path.join(src_dir, file[:-4])
        if not os.path.exists(src_dir):
            raise RuntimeError('Missing Folder {}'.format(src_dir))

        sql_files = [x for x in os.listdir(src_dir) if x.endswith('.sql')]
        sql_file = os.path.join(src_dir, sql_files[0])
        # #print(sql_file)
        # return
        self.chelt_db.run_sql_file(sql_file)
        if import_files:
            print('import_files not yet implemented')
            # attachments = [x for x in os.listdir(src_dir) if
            #                (x.endswith('.jpg') or
            #                 x.endswith('.pdf') or
            #                 x.endswith('.csv') or
            #                 x.endswith('.CSV')
            #                 )]
            # tab = []
            # for file_name in attachments:
            #     try:
            #         # #print(file_name)
            #         table_id, orig_name = file_name.split('+')
            #         fil = os.path.join(src_dir, file_name)
            #         self.alimentari.changeCellContent('file', fil, 'id', table_id)
            #         self.alimentari.changeCellContent('file_name', str(orig_name), 'id', table_id)
            #         # #print(user_id, table_name, table_id, orig_name)
            #     except:
            #         #print('could not import {}, name not ok'.format(file_name))
            #     tup = (table_id, orig_name, file_name)
            #     tab.append(tup)
        if os.path.exists(src_dir):
            shutil.rmtree(src_dir)
        return zip_file

    def erase_chelt_traces(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # for i in self.chelt_db.checkProcess():
        #     #print(i)
        delete_real_db_tables = False
        if self.has_cheltuieli_real:
            delete_real_db_tables = True
        self.chelt_db.killAllProcess()

        # if delete_real_db_tables:
        if 'banca' in self.chelt_db.allAvailableTablesInDatabase:
            self.chelt_db.drop_table_list(list(app_real_expenses.keys()))
        self.chelt_db.drop_table_list(list(app_chelt_tables.keys()))

    # def zip_profile_files(self, src_dir, output_file):
    #     #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #                                                               sys._getframe().f_back.f_code.co_name))
    #     relroot = os.path.abspath(os.path.join(src_dir, os.pardir))
    #     with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zip:
    #         for root, dirs, files in os.walk(src_dir):
    #             # add directory (needed for empty dirs)
    #             zip.write(root, os.path.relpath(root, relroot))
    #             for file in files:
    #                 filename = os.path.join(root, file)
    #                 if os.path.isfile(filename):  # regular files only
    #                     arcname = os.path.join(os.path.relpath(root, relroot), file)
    #                     zip.write(filename, arcname)
    #     return output_file

    def unzip_profile_files(self, src_file, output_dir):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        with zipfile.ZipFile(src_file, 'r') as zip_ref:
            zip_ref.extractall(output_dir)
        return output_dir

    @property
    def backup_profile_dir(self):
        backup_profile_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                          '{:09d}'.format(self.id))
        if os.path.exists(backup_profile_dir):
            return backup_profile_dir
        else:
            return None

    @property
    def last_profile_backup(self):
        try:
            all_profile_backups = os.listdir(self.backup_profile_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = last_profile_backup.split('_')[:7]
            last_profile_backup = (('{}_' * len(last_profile_backup)).format(*last_profile_backup))
            last_profile_backup = last_profile_backup[:-1]
            return last_profile_backup
        except:
            return None

    @property
    def last_profile_backup_file(self):
        all_profile_backups = os.listdir(self.backup_profile_dir)
        all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
        all_profile_backups.sort(reverse=True)
        last_profile_backup = all_profile_backups[0]
        last_profile_backup = os.path.join(self.backup_profile_dir, last_profile_backup)
        return last_profile_backup

    @property
    def backup_chelt_plan_dir(self):
        backup_profile_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                          '{:09d}'.format(self.id), 'chelt_plan')
        if os.path.exists(backup_profile_dir):
            return backup_profile_dir
        else:
            return None

    @property
    def last_chelt_plan_backup(self):
        try:
            all_profile_backups = os.listdir(self.backup_chelt_plan_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = last_profile_backup.split('_')[:7]
            last_profile_backup = (('{}_' * len(last_profile_backup)).format(*last_profile_backup))
            last_profile_backup = last_profile_backup[:-1]
            return last_profile_backup
        except:
            return None

    @property
    def last_chelt_plan_backup_file(self):
        try:
            all_profile_backups = os.listdir(self.backup_chelt_plan_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = os.path.join(self.backup_chelt_plan_dir, last_profile_backup)
            return last_profile_backup
        except:
            return None

    @property
    def backup_income_plan_dir(self):
        backup_profile_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                          '{:09d}'.format(self.id), 'income_plan')
        if os.path.exists(backup_profile_dir):
            return backup_profile_dir
        else:
            return None

    @property
    def last_income_plan_backup(self):
        try:
            all_profile_backups = os.listdir(self.backup_income_plan_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = last_profile_backup.split('_')[:7]
            last_profile_backup = (('{}_' * len(last_profile_backup)).format(*last_profile_backup))
            last_profile_backup = last_profile_backup[:-1]
            return last_profile_backup
        except:
            return None

    @property
    def last_income_plan_backup_file(self):
        all_profile_backups = os.listdir(self.backup_income_plan_dir)
        all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
        all_profile_backups.sort(reverse=True)
        last_profile_backup = all_profile_backups[0]
        last_profile_backup = os.path.join(self.backup_income_plan_dir, last_profile_backup)
        return last_profile_backup

    def export_real_expenses_csvs(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
        output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                  '{:09d}'.format(self.id), 'real_expenses',
                                  '{}_{:09d}'.format(tim, self.id))
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        real_expenses_bkp_tables = ['banca', 'knowntrans', ]
        tables = {}
        for tab in real_expenses_bkp_tables:
            tables[tab] = {'id_users': self.id}

        sql_query = self.chelt_db.return_sql_text(tables)
        output_sql_file = os.path.join(output_dir, '{}_{:09d}.sql'.format(tim, self.id))
        FILE = open(output_sql_file, "w", encoding="utf-8")
        FILE.writelines(sql_query)
        FILE.close()

        match = ('id_users', self.id)
        rows = self.imported_csv.returnRowsWhere(match)
        for rr in rows:
            # print('rr**', rr)
            id_ = rr[0]
            file_name = rr[-1]
            currentConto = rr[self.imported_csv.columnsNames.index('banca')]
            matches = [('name', currentConto), ('id_users', self.id)]
            # print('matches**', matches)
            banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]

            bank_dir = os.path.join(output_dir, banca, currentConto)
            if not os.path.exists(bank_dir):
                os.makedirs(bank_dir)

            output_file = os.path.join(bank_dir, file_name)
            # print(output_file)
            file_content = self.imported_csv.returnCellsWhere('file', ('id', id_))[0]
            self.imported_csv.write_file(file_content, output_file)
        # #####
        output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
        zip_file = self.zip_profile_files(output_dir, output_zip)
        if os.path.exists(zip_file):
            shutil.rmtree(output_dir)
        print('finished backup', output_zip)
        return zip_file

    # def import_real_expenses_csvs(self, zip_file, import_files=False):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     output_dir, file = os.path.split(zip_file)
    #     src_dir = self.unzip_profile_files(zip_file, output_dir)
    #     src_dir = os.path.join(src_dir, file[:-4])
    #     if not os.path.exists(src_dir):
    #         raise RuntimeError('Missing Folder {}'.format(src_dir))
    #
    #     sql_files = [x for x in os.listdir(src_dir) if x.endswith('.sql')]
    #     sql_file = os.path.join(src_dir, sql_files[0])
    #     # #print(sql_file)
    #     # return
    #     self.chelt_db.run_sql_file(sql_file)
    #     if import_files:
    #         print('import_files not yet implemented')
    #         # attachments = [x for x in os.listdir(src_dir) if
    #         #                (x.endswith('.jpg') or
    #         #                 x.endswith('.pdf') or
    #         #                 x.endswith('.csv') or
    #         #                 x.endswith('.CSV')
    #         #                 )]
    #         # tab = []
    #         # for file_name in attachments:
    #         #     try:
    #         #         # #print(file_name)
    #         #         table_id, orig_name = file_name.split('+')
    #         #         fil = os.path.join(src_dir, file_name)
    #         #         self.alimentari.changeCellContent('file', fil, 'id', table_id)
    #         #         self.alimentari.changeCellContent('file_name', str(orig_name), 'id', table_id)
    #         #         # #print(user_id, table_name, table_id, orig_name)
    #         #     except:
    #         #         #print('could not import {}, name not ok'.format(file_name))
    #         #     tup = (table_id, orig_name, file_name)
    #         #     tab.append(tup)
    #     if os.path.exists(src_dir):
    #         shutil.rmtree(src_dir)
    #     return zip_file

    @property
    def backup_real_expenses_dir(self):
        backup_profile_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
                                          '{:09d}'.format(self.id), 'real_expenses')
        if os.path.exists(backup_profile_dir):
            return backup_profile_dir
        else:
            return None

    @property
    def last_real_expenses_backup(self):
        try:
            all_profile_backups = os.listdir(self.backup_real_expenses_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = last_profile_backup.split('_')[:7]
            last_profile_backup = (('{}_' * len(last_profile_backup)).format(*last_profile_backup))
            last_profile_backup = last_profile_backup[:-1]
            return last_profile_backup
        except:
            return None

    @property
    def last_real_expenses_backup_file(self):
        try:
            all_profile_backups = os.listdir(self.backup_real_expenses_dir)
            all_profile_backups = [x for x in all_profile_backups if x.endswith('.zip')]
            all_profile_backups.sort(reverse=True)
            last_profile_backup = all_profile_backups[0]
            last_profile_backup = os.path.join(self.backup_real_expenses_dir, last_profile_backup)
            return last_profile_backup
        except:
            return None


class Income:
    def __init__(self, chelt_db, income_table):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        self.dataBase = chelt_db
        self.income_table = income_table
        CheckCheltRequiredFiles(self.dataBase, self.income_table)
        pth2src = os.path.dirname(__file__)
        # self.taxes_file = r"static\taxes.csv"
        self.displayExpensesTableHead = ['table', 'name', 'brutto', 'netto', 'uberweisung', 'myconto', 'payDay', 'freq',
                                         'in_salary']
        self.taxes_file = os.path.join(pth2src, 'static', 'taxes.csv')
        self.tax_array, self.tax_header = self.conv_csv_to_np(skipHeader=1)

        self.selectedStartDate = None
        self.selectedEndDate = None
        self.conto = None
        self.tableHead = None
        self.income = None

    def apply_taxes_to_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        for inc in self.incomes_for_time_interval:
            if inc.is_salary:
                # #print('####', inc.id, inc.name, inc.payments_for_interval)
                inc.basic_brutto_35h_salary = inc.value
                other_incomes_with_salary = self.find_other_incomes_with_salary_tax()
                brutto = inc.basic_brutto_35h_salary
                # #print('******inc.basic_brutto_35h_salary', inc.basic_brutto_35h_salary)
                for i in other_incomes_with_salary:
                    if i.value:
                        brutto += i.value
                    else:
                        brutto += inc.basic_brutto_35h_salary * float(i.proc)
                inc.monthly_35h_brutto_salary = brutto
                # #print('******inc.monthly_35h_brutto_salary', inc.monthly_35h_brutto_salary)
                taxes = ['lohnsteuer', 'rentenvers', 'arbeitslosvers', 'krankenvers', 'privatvers']
                for tax in taxes:
                    res = round(self.calculate_tax(inc, tax), 2)
                    exec('inc.{} = {}'.format(tax, res))
                inc.brutto = round(inc.brutto_monthly_salary, 2)

        for inc in self.incomes_for_time_interval:
            if inc.tax == 'bonus':
                for payday in inc.payments_for_interval:
                    income_with_same_payday = self.find_salary_with_same_payday(payday)
                    if not income_with_same_payday:
                        print(inc.id, inc.name, payday)
                    inc.steuerklasse = income_with_same_payday.steuerklasse
                    if not inc.value:
                        inc.value = float(inc.proc) * income_with_same_payday.brutto_monthly_salary
                    inc.brutto = round(float(inc.value), 2)

                    taxes = ['lohnsteuer', 'rentenvers', 'arbeitslosvers']
                    for tax in taxes:
                        res = self.calculate_tax(inc, tax)
                        exec('inc.{} = {}'.format(tax, res))
            elif not inc.tax:
                inc.brutto = round(float(inc.value), 2)

    def find_salary_with_same_payday(self, payday):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        for inc in self.incomes_for_time_interval:
            if inc.is_salary:
                if payday in inc.payments_for_interval:
                    return inc

    def calculate_tax(self, income, steuer):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        indx_row = np.where((self.tax_array[:, self.tax_header.index('tax')] == income.tax) &
                            (self.tax_array[:, self.tax_header.index('steuerklasse')].astype(
                                int) == income.steuerklasse))

        lohnteuer_proc = self.tax_array[indx_row, self.tax_header.index(steuer)]
        lohnteuer_proc = float(lohnteuer_proc[0, 0]) / 100

        if income.is_salary:
            lohnteuer = float(income.brutto_monthly_salary) * lohnteuer_proc
        else:
            lohnteuer = float(income.value) * lohnteuer_proc
        return round(lohnteuer, 2)

    def convert_to_tabel(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table = [('table', 'name', 'brutto', 'taxes', 'netto', 'myconto', 'payDay', 'freq')]
        for income in self.incomes_for_time_interval:
            for datum in income.payments_for_interval:
                if not income.brutto and not income.gesetzliche_abzuge and not income.netto:
                    continue
                tup = (
                    income.table, income.name, income.brutto, income.gesetzliche_abzuge, income.netto, income.myconto,
                    datum.date(), income.freq)
                table.append(tup)
        table = np.atleast_2d(table)
        return table

    def convert_to_salary_tabel(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table = [('table', 'name', 'brutto', 'lohnsteuer', 'rentenvers', 'arbeitslosvers', 'gesetzliche_abzuge',
                  'netto', 'krankenvers', 'privatvers', 'abzuge', 'uberweisung', 'myconto', 'payDay', 'freq')]
        brutto = 0
        taxes = 0
        netto = 0
        abzuge = 0
        uberweisung = 0
        for income in self.incomes_for_time_interval:
            if not income.in_salary:
                # print('++++++not in salary', income.name)
                continue
            for datum in income.payments_for_interval:
                if not income.brutto and not income.gesetzliche_abzuge and not income.netto:
                    continue
                tup = (income.table,
                       income.name,
                       income.brutto,
                       income.lohnsteuer,
                       income.rentenvers,
                       income.arbeitslosvers,
                       income.gesetzliche_abzuge,
                       income.netto,
                       income.krankenvers,
                       income.privatvers,
                       income.abzuge,
                       income.uberweisung,
                       income.myconto,
                       datum.date(),
                       income.freq)
                table.append(tup)
                try:
                    brutto += income.brutto
                    if income.gesetzliche_abzuge:
                        taxes += income.gesetzliche_abzuge
                    if income.abzuge:
                        abzuge += income.abzuge
                    netto += float(income.netto)
                    uberweisung += float(income.uberweisung)
                except:
                    print(income.name, income.brutto, income.netto)
        table = np.atleast_2d(table)
        return table, brutto, round(taxes, 2), netto, abzuge, uberweisung

    def convert_to_total_income_tabel(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table = [('table', 'name', 'brutto', 'lohnsteuer', 'rentenvers', 'arbeitslosvers', 'gesetzliche_abzuge',
                  'netto', 'krankenvers', 'privatvers', 'abzuge', 'uberweisung', 'myconto', 'payDay', 'freq',
                  'in_salary')]
        salary_brutto = 0
        salary_gesetzliche_abzuge = 0
        salary_netto = 0
        salary_abzuge = 0
        salary_uberweisung = 0
        brutto = 0
        taxes = 0
        netto = 0
        abzuge = 0
        uberweisung = 0
        for income in self.incomes_for_time_interval:
            for datum in income.payments_for_interval:
                if not income.brutto and not income.gesetzliche_abzuge and not income.netto:
                    continue
                tup = (income.table,
                       income.name,
                       income.brutto,
                       income.lohnsteuer,
                       income.rentenvers,
                       income.arbeitslosvers,
                       income.gesetzliche_abzuge,
                       income.netto,
                       income.krankenvers,
                       income.privatvers,
                       income.abzuge,
                       income.uberweisung,
                       income.myconto,
                       datum.date(),
                       income.freq,
                       income.in_salary,
                       )
                table.append(tup)
                try:
                    if income.in_salary:
                        salary_brutto += income.brutto
                        if income.gesetzliche_abzuge:
                            salary_gesetzliche_abzuge += income.gesetzliche_abzuge
                        salary_netto += float(income.netto)
                        if income.abzuge:
                            salary_abzuge += income.abzuge
                        salary_uberweisung += float(income.uberweisung)
                    brutto += income.brutto
                    if income.gesetzliche_abzuge:
                        taxes += income.gesetzliche_abzuge
                    if income.abzuge:
                        abzuge += income.abzuge
                    netto += float(income.netto)
                    uberweisung += float(income.uberweisung)
                except:
                    print(income.name, income.brutto, income.netto)
        table = np.atleast_2d(table)
        result = (table, brutto, round(taxes, 2), netto, abzuge, uberweisung, salary_brutto, salary_gesetzliche_abzuge,
                  salary_netto, salary_abzuge, salary_uberweisung)
        return result

    def conv_csv_to_np(self, delimiter=';', skipHeader=None):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        array = []
        header = []
        with open(self.taxes_file, 'r') as file:
            reader = csv.reader(file, delimiter=delimiter)
            for i, row in enumerate(reader):
                if skipHeader:
                    if i < skipHeader:
                        header.append(row)
                        continue
                array.append(row)
            array = np.atleast_2d(array)
        if skipHeader == 1:
            header = header[0]

        return array, header

    def get_all_income_rows(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        vals = self.income_table.returnAllRecordsFromTable()
        all_incomes = []
        for row in vals:
            row = list(row)
            income = Cheltuiala(row, self.income_table.columnsNames)
            income.set_table(self.income_table.tableName)
            all_incomes.append(income)
        return all_incomes

    def filter_income_for_interval(self, all_income_rows):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        incomes_interval = []
        for inc in all_income_rows:
            payments_in_interval = None
            if self.myconto == 'all':
                payments_in_interval = inc.calculate_payments_in_interval(self.selectedStartDate, self.selectedEndDate)
            elif self.myconto == inc.myconto:
                payments_in_interval = inc.calculate_payments_in_interval(self.selectedStartDate, self.selectedEndDate)
            if payments_in_interval:
                inc.payments_for_interval = payments_in_interval
                incomes_interval.append(inc)
        return incomes_interval

    def find_other_incomes_with_salary_tax(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        other_incomes_with_salary = []
        for i in self.incomes_for_time_interval:
            if i.tax == 'salary' and i.name != 'Salariu':
                other_incomes_with_salary.append(i)
        return other_incomes_with_salary

    def prepareTablePlan(self, conto, selectedStartDate, selectedEndDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.selectedStartDate = selectedStartDate
        self.selectedEndDate = selectedEndDate
        self.myconto = conto

        all_income_rows = self.get_all_income_rows()
        self.incomes_for_time_interval = self.filter_income_for_interval(all_income_rows)
        self.apply_taxes_to_salary()
        # table = self.convert_to_tabel()
        result = self.convert_to_total_income_tabel()
        table, self.brutto, self.taxes, self.netto, self.abzuge, self.uberweisung, self.salary_brutto, \
        self.salary_gesetzliche_abzuge, self.salary_netto, self.salary_abzuge, self.salary_uberweisung = result

        self.tableHead, self.income = list(table[0]), table[1:]

    def get_salary_income(self, month):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.selectedStartDate, self.selectedEndDate = get_monthly_interval(month)
        self.myconto = 'EC'

        all_income_rows = self.get_all_income_rows()
        self.incomes_for_time_interval = self.filter_income_for_interval(all_income_rows)
        self.apply_taxes_to_salary()
        table, brutto, taxes, netto, abzuge, uberweisung = self.convert_to_salary_tabel()
        return table, brutto, taxes, netto, abzuge, uberweisung

    def get_total_monthly_income(self, month):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.selectedStartDate, self.selectedEndDate = get_monthly_interval(month)
        self.myconto = 'all'

        all_income_rows = self.get_all_income_rows()
        self.incomes_for_time_interval = self.filter_income_for_interval(all_income_rows)
        self.apply_taxes_to_salary()
        table, brutto, taxes, netto, abzuge, uberweisung = self.convert_to_total_income_tabel()
        return table, brutto, taxes, netto, abzuge, uberweisung

    def convert_to_display_table(self, tableHead, table, displayTableHead):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        newTableData = np.empty([table.shape[0], len(displayTableHead)], dtype=object)
        for i, col in enumerate(displayTableHead):
            indxCol = tableHead.index(col)
            newTableData[:, i] = table[:, indxCol]

        return displayTableHead, newTableData

    @property
    def monthly_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        monthly_income = 0
        for row in self.income:
            if row[self.tableHead.index('freq')] == 1:
                monthly_income += float(row[self.tableHead.index('netto')])
        return round(monthly_income, 2)

    @property
    def irregular_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        irregular_income = 0
        for row in self.income:
            if row[self.tableHead.index('freq')] > 1:
                irregular_income += float(row[self.tableHead.index('netto')])
        return round(irregular_income, 2)


class Cheltuiala:
    def __init__(self, row, tableHead):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('#####', tableHead)
        self.tableHead = tableHead
        self.read_row(row)
        self.lohnsteuer = None
        self.rentenvers = None
        self.arbeitslosvers = None
        self.krankenvers = None
        self.privatvers = None
        self.brutto = None

    def read_row(self, row):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        for col in self.tableHead:
            exec('self.{} = row[self.tableHead.index("{}")]'.format(col, col))

        if self.pay_day is None:
            self.pay_day = calculate_last_day_of_month(self.valid_from.month, self.valid_from.year)

        if self.auto_ext is None or self.auto_ext == 0:
            self.auto_ext = False
        else:
            self.auto_ext = True

    def set_table(self, table_name):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.table = table_name

    @property
    def first_payment(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        try:
            first_payment = datetime(self.valid_from.year, self.valid_from.month, self.pay_day)
        except:
            # #print(self.id, self.table, self.name)
            # #print(self.valid_from.year, self.valid_from.month, self.pay_day)
            # first_payment = calculate_last_day_of_month(selectedStartDate.month)
            first_payment = datetime(self.valid_from.year, self.valid_from.month,
                                     calculate_last_day_of_month(self.valid_from.month, self.valid_from.year))
        return first_payment

    @property
    def is_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.name == 'Salariu' and self.freq == 1 and self.value:
            is_salary = True
        else:
            is_salary = False
        return is_salary

    @property
    def basic_brutto_35h_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        return self.val

    @basic_brutto_35h_salary.setter
    def basic_brutto_35h_salary(self, income):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.val = float(income)

    @property
    def monthly_35h_brutto_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        return self.val

    @monthly_35h_brutto_salary.setter
    def monthly_35h_brutto_salary(self, income):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.val = float(income)

    @property
    def hourly_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        hourly_salary = self.monthly_35h_brutto_salary / 4 / 35
        return hourly_salary

    @property
    def brutto_monthly_salary(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        val = self.hourly_salary * self.hours * 4
        return val

    @property
    def gesetzliche_abzuge(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        try:
            gesetzliche_abzuge = round(self.lohnsteuer + self.rentenvers + self.arbeitslosvers, 2)
        except:
            return None
        return gesetzliche_abzuge

    @property
    def abzuge(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        try:
            abzuge = round(self.krankenvers + self.privatvers, 2)
        except:
            return None
        return abzuge

    @property
    def netto(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.gesetzliche_abzuge and self.brutto:
            netto = round(self.brutto - self.gesetzliche_abzuge, 2)
        else:
            netto = self.brutto
        return netto

    @property
    def uberweisung(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.netto and self.is_salary:
            uberweisung = round(float(self.netto) - self.abzuge, 2)
        else:
            uberweisung = self.netto
        return uberweisung

    def list_of_payments_valid_from_till_selected_end_date(self, selectedEndDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        list_of_payments_till_selected_end_date = []
        if self.valid_from <= self.first_payment.date() <= selectedEndDate:
            list_of_payments_till_selected_end_date.append(self.first_payment)

        next_payment = self.first_payment + relativedelta(months=self.freq)
        if next_payment.day != self.pay_day:
            try:
                next_payment = datetime(next_payment.year, next_payment.month, self.pay_day)
            except:
                next_payment = datetime(next_payment.year, next_payment.month,
                                        calculate_last_day_of_month(next_payment.month, next_payment.year))
        if self.valid_from <= next_payment.date() <= selectedEndDate:
            list_of_payments_till_selected_end_date.append(next_payment)

        while next_payment.date() <= selectedEndDate:
            next_payment = next_payment + relativedelta(months=self.freq)
            if next_payment.day != self.pay_day:
                try:
                    next_payment = datetime(next_payment.year, next_payment.month, self.pay_day)
                except:
                    # #print('#####', next_payment.year, next_payment.month,
                    #                         calculate_last_day_of_month(next_payment.month, next_payment.year))
                    next_payment = datetime(next_payment.year, next_payment.month,
                                            calculate_last_day_of_month(next_payment.month, next_payment.year))
            if self.valid_from <= next_payment.date() <= selectedEndDate:
                list_of_payments_till_selected_end_date.append(next_payment)
        return list_of_payments_till_selected_end_date

    def cut_all_before_selectedStartDate(self, lista, selectedStartDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        new_list = []
        for date in lista:
            if date.date() >= selectedStartDate:
                new_list.append(date)
        return new_list

    def cut_all_after_valid_to(self, lista):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        new_list = []
        for date in lista:
            if date.date() <= self.valid_to:
                new_list.append(date)
        return new_list

    def calculate_payments_in_interval(self, selectedStartDate, selectedEndDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        list_of_payments_valid_from_till_selected_end_date = self.list_of_payments_valid_from_till_selected_end_date(
            selectedEndDate)
        # #print(20*'*')
        # for i in list_of_payments_valid_from_till_selected_end_date:
        #     #print(i)
        # #print(20*'*')

        list_of_payments_selected_start_date_till_selected_end_date = self.cut_all_before_selectedStartDate(
            list_of_payments_valid_from_till_selected_end_date, selectedStartDate)
        # #print(20*'*')
        # for i in list_of_payments_selected_start_date_till_selected_end_date:
        #     #print(i)
        # #print(20*'*')

        if self.valid_to and self.valid_to < selectedEndDate and not self.auto_ext:
            list_of_payments_selected_start_date_till_selected_end_date = self.cut_all_after_valid_to(
                list_of_payments_selected_start_date_till_selected_end_date)
            # #print(20*'*')
            # for i in list_of_payments_selected_start_date_till_selected_end_date:
            #     #print(i)
            # #print(20*'*')

        return list_of_payments_selected_start_date_till_selected_end_date

    @property
    def first_payment_date(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        first_payment_date = datetime(self.valid_from.year, self.valid_from.month, self.pay_day)
        return first_payment_date

    @property
    def payments_for_interval(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        return self.pfi

    @payments_for_interval.setter
    def payments_for_interval(self, payments_days):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.pfi = payments_days


class CheltuieliPlanificate:
    def __init__(self, chelt_db, chelt_plan, yearly_plan, yearly_all, id_users):  # myAccountsTable
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        self.tableHead = ['id', 'category', 'name', 'value', 'myconto', 'freq', 'pay_day', 'valid_from', 'valid_to',
                          'auto_ext']
        self.displayExpensesTableHead = ['category', 'name', 'value', 'myconto', 'payDay', 'freq']
        self.dataBase = chelt_db
        self.chelt_plan = chelt_plan
        self.yearly_plan = yearly_plan
        self.yearly_all = yearly_all
        # self.myAccountsTable = myAccountsTable
        self.id_users = id_users
        CheckCheltRequiredFiles(self.dataBase, self.chelt_plan, self.yearly_plan)

    @property
    def myContos(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        return list(set(self.yearly_all.returnColumn('myconto')))

    @property
    def categories(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        all_cat = list(set(self.yearly_all.returnColumn('category')))
        # all_cat = [s.lower() for s in all_cat if s is not None]
        return all_cat

    @property
    def tot_val_of_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.expenses.shape == (1, 0):
            return 0
        allValues = self.expenses[:, self.tableHead.index('value')]
        if None in allValues:
            allValues = allValues[allValues != np.array(None)]
        totalVal = round(sum(allValues.astype(float)), 2)
        return totalVal

    @property
    def tot_no_of_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        try:
            allValues = self.expenses[:, self.tableHead.index('value')]
            if None in allValues:
                allValues = allValues[allValues != np.array(None)]
            return len(allValues)
        except:
            return None

    @property
    def tot_val_of_monthly_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.expenses.shape == (1, 0):
            return 0
        indxMonthly = np.where(self.expenses[:, self.tableHead.index('freq')] == 1)[0]
        monthly = self.expenses[indxMonthly, self.tableHead.index('value')]
        if None in monthly:
            monthly = monthly[monthly != np.array(None)]
        totalMonthly = round(sum(monthly.astype(float)), 2)
        return totalMonthly

    @property
    def tot_no_of_monthly_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        try:
            indxMonthly = np.where(self.expenses[:, self.tableHead.index('freq')] == 1)[0]
            monthly = self.expenses[indxMonthly, self.tableHead.index('value')]
            return monthly.shape[0]
        except:
            return None

    @property
    def tot_val_of_irregular_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if self.expenses.shape == (1, 0):
            return 0
        indxMonthly = np.where(self.expenses[:, self.tableHead.index('freq')] != 1)[0]
        monthly = self.expenses[indxMonthly, self.tableHead.index('value')]
        if None in monthly:
            monthly = monthly[monthly != np.array(None)]
        totalMonthly = round(sum(monthly.astype(float)), 2)
        return totalMonthly

    @property
    def tot_no_of_irregular_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        try:
            indxMonthly = np.where(self.expenses[:, self.tableHead.index('freq')] != 1)[0]
            monthly = self.expenses[indxMonthly, self.tableHead.index('value')]
            return monthly.shape[0]
        except:
            return None

    @property
    def totals_summary(self):
        totals = {'tot_of_expenses': (self.tot_val_of_expenses, self.tot_no_of_expenses),
                  'irregular_expenses': (self.tot_val_of_irregular_expenses, self.tot_no_of_irregular_expenses),
                  'monthly_expenses': (self.tot_val_of_monthly_expenses, self.tot_no_of_monthly_expenses),
                  }
        for bank, values in self.expenses_per_conto.items():
            if bank == 'total':
                continue
            totals[bank] = values
        return totals

    @property
    def expenses_per_conto(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.expenses.shape == (1, 0):
            return None
        totals_per_conto = {}
        contos = np.unique(self.expenses[:, self.tableHead.index('myconto')])
        total_amount = 0
        total_transactions = 0
        # for con in contos:
        for con in self.myContos:
            conto_arr = self.expenses[self.expenses[:, self.tableHead.index('myconto')] == con]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[con] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        return totals_per_conto

    @property
    def expenses_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.expenses.shape == (1, 0):
            return None
        # categories = list(set(self.expenses[:, self.tableHead.index('category')]))
        total_amount = 0
        total_transactions = 0
        for cat in self.categories:
            conto_arr = self.expenses[self.expenses[:, self.tableHead.index('category')] == cat]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))

        return totals_per_conto

    @property
    def expenses_per_names(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.expenses.shape == (1, 0):
            return None
        categories = list(set(self.expenses[:, self.tableHead.index('name')]))
        total_amount = 0
        total_transactions = 0
        for cat in categories:
            conto_arr = self.expenses[self.expenses[:, self.tableHead.index('name')] == cat]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        return totals_per_conto

    @property
    def expenses_per_conto_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.expenses.shape == (1, 0):
            return None
        contos = list(set(self.expenses[:, self.tableHead.index('myconto')]))
        total_amount = 0
        total_transactions = 0
        per_category_only = {}
        for con in contos:
            conto_arr = self.expenses[self.expenses[:, self.tableHead.index('myconto')] == con]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_category = {}

            categories = list(set(conto_arr[:, self.tableHead.index('category')]))
            # total_amount = 0
            # total_transactions = 0
            for cat in categories:
                cat_arr = conto_arr[conto_arr[:, self.tableHead.index('category')] == cat]
                col = cat_arr[:, self.tableHead.index('value')]
                tot_cat_val = sum(col)
                no_of_cat_transactions = len(col)
                totals_per_category[cat] = (tot_cat_val, no_of_cat_transactions)
                if cat in per_category_only.keys():
                    pc_tot_val, pc_to_no_of_transactions = per_category_only[cat]
                    pc_tot_val += tot_cat_val
                    pc_to_no_of_transactions += no_of_cat_transactions
                    per_category_only[cat] = (pc_tot_val, pc_to_no_of_transactions)
                else:
                    per_category_only[cat] = (tot_cat_val, no_of_cat_transactions)
            totals_per_conto[con] = (tot_val, no_of_transactions, totals_per_category)
            total_amount += tot_val
            total_transactions += no_of_transactions

        totals_per_conto['all'] = (total_amount, total_transactions, per_category_only)
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        return totals_per_conto

    @property
    def all_planned_values(self):
        rows = self.chelt_plan.returnAllRecordsFromTable()
        rows.insert(0, self.chelt_plan.columnsNames)
        return rows

    # income#################################################################################
    @property
    def tot_no_of_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.income.shape[1] > 0:
            allValues = self.income[:, self.tableHead.index('value')]
            if None in allValues:
                allValues = allValues[allValues != np.array(None)]
            return len(allValues)
        else:
            return 0

    @property
    def tot_val_of_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.income.shape[1] > 0:
            allValues = self.income[:, self.tableHead.index('value')]
            if None in allValues:
                allValues = allValues[allValues != np.array(None)]
            totalVal = round(sum(allValues.astype(float)), 2)
            return totalVal
        else:
            return 0

    @property
    def income_per_conto(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.income.shape == (1, 0):
            return None
        totals_per_conto = {}
        contos = np.unique(self.income[:, self.tableHead.index('myconto')])
        total_amount = 0
        total_transactions = 0
        for con in contos:
            conto_arr = self.income[self.income[:, self.tableHead.index('myconto')] == con]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[con] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['total'] = (total_amount, total_transactions)
        return totals_per_conto

    @property
    def income_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.income.shape == (1, 0):
            return None
        categories = list(set(self.income[:, self.tableHead.index('category')]))
        total_amount = 0
        total_transactions = 0
        for cat in categories:
            conto_arr = self.income[self.income[:, self.tableHead.index('category')] == cat]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        return totals_per_conto

    @property
    def income_per_conto_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.income.shape == (1, 0):
            return None
        contos = list(set(self.income[:, self.tableHead.index('myconto')]))
        total_amount = 0
        total_transactions = 0
        per_category_only = {}
        for con in contos:
            conto_arr = self.income[self.income[:, self.tableHead.index('myconto')] == con]
            col = conto_arr[:, self.tableHead.index('value')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_category = {}

            categories = list(set(conto_arr[:, self.tableHead.index('category')]))
            # total_amount = 0
            # total_transactions = 0
            for cat in categories:
                cat_arr = conto_arr[conto_arr[:, self.tableHead.index('category')] == cat]
                col = cat_arr[:, self.tableHead.index('value')]
                tot_cat_val = sum(col)
                no_of_cat_transactions = len(col)
                totals_per_category[cat] = (tot_cat_val, no_of_cat_transactions)
                if cat in per_category_only.keys():
                    pc_tot_val, pc_to_no_of_transactions = per_category_only[cat]
                    pc_tot_val += tot_cat_val
                    pc_to_no_of_transactions += no_of_cat_transactions
                    per_category_only[cat] = (pc_tot_val, pc_to_no_of_transactions)
                else:
                    per_category_only[cat] = (tot_cat_val, no_of_cat_transactions)
            totals_per_conto[con] = (tot_val, no_of_transactions, totals_per_category)
            total_amount += tot_val
            total_transactions += no_of_transactions

        totals_per_conto['all'] = (total_amount, total_transactions, per_category_only)
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        return totals_per_conto

    @property
    def tot_no_of_expenses_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        tot = self.tot_no_of_expenses + self.tot_no_of_income
        return tot

    @property
    def tot_val_of_expenses_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        return round(self.tot_val_of_expenses + self.tot_val_of_income, 2)

    # income##################################################################################

    # prepareTablePlan##################################################################################
    def default_interval(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}'.format(__name__, __class__, sys._getframe().f_code.co_name))
        # #print('Caller : ', sys._getframe().f_back.f_code.co_name)
        startDate = datetime(datetime.now().year, datetime.now().month, 1)
        if datetime.now().month != 12:
            mnth = datetime.now().month + 1
            lastDayOfMonth = datetime(datetime.now().year, mnth, 1) - timedelta(days=1)
        else:
            lastDayOfMonth = datetime(datetime.now().year + 1, 1, 1) - timedelta(days=1)
        return startDate, lastDayOfMonth

    def filter_dates(self, all_chelt, selectedStartDate, selectedEndDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        remaining = []
        for chelt in all_chelt:
            # #print('++', chelt.category, chelt.name, chelt.id, chelt.pay_day)
            payments_in_interval = chelt.calculate_payments_in_interval(selectedStartDate, selectedEndDate)
            # #print(payments_in_interval)
            # if chelt.name == 'Steuererklärung_2022':
            #     #print(chelt.table, chelt.name, chelt.id, chelt.pay_day, payments_in_interval)
            if isinstance(payments_in_interval, list):
                chelt.payments_for_interval = payments_in_interval
                # #print(chelt.table, chelt.name, chelt.id, chelt.pay_day, chelt.payments_for_interval)
                if chelt.payments_for_interval:
                    remaining.append(chelt)
        return remaining

    def filter_conto(self, chelt_list, conto, hideintercontotrans):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        # #print('ÖÖÖÖÖÖÖÖintercontotrans', intercontotrans)
        remaining = []
        for ch in chelt_list:
            if hideintercontotrans and ch.category == 'intercontotrans':
                continue
            if conto != 'all' and ch.myconto != conto:
                continue
            remaining.append(ch)
        return remaining

    def split_expenses_income(self, chelt):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        arr_expenses = []
        arr_income = []
        for ch in chelt:
            if ch.value == 0:
                continue
            for payment_day in ch.payments_for_interval:
                variables = vars(ch)
                row = []  # ch.table
                for col in self.tableHead:
                    val = variables[col]
                    row.append(val)
                # #print('######', payment_day, type(payment_day))
                row.append(payment_day.date())
                if ch.value and ch.value > 0:
                    arr_income.append(row)
                else:
                    arr_expenses.append(row)
        arr_expenses = np.atleast_2d(arr_expenses)
        arr_income = np.atleast_2d(arr_income)
        # self.tableHead.insert(0, 'table')
        self.tableHead.append('payDay')
        return arr_expenses, arr_income

    def get_all_sql_vals(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        all_chelt = []
        # active_table = self.chelt_plan
        # active_table_head = active_table.columnsNames
        # #print('******active_table_head', active_table_head)
        # if 'table' in self.tableHead:
        #     self.tableHead.remove('table')
        if 'payDay' in self.tableHead:
            self.tableHead.remove('payDay')
        # check = all(item in active_table_head for item in self.tableHead)
        # if check:
        # vals = self.chelt_plan.returnAllRecordsFromTable()
        match = ('id_users', self.id_users)
        vals = self.chelt_plan.returnRowsWhere(match)
        for row in vals:
            row = list(row)
            chelt = Cheltuiala(row, self.chelt_plan.columnsNames)
            all_chelt.append(chelt)
        return all_chelt

    def prepareTablePlan(self, conto, selectedStartDate, selectedEndDate, hideintercontotrans):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        # #print(selectedStartDate, selectedEndDate)
        all_chelt = self.get_all_sql_vals()
        # for i in all_chelt:
        # #print(i.freq)
        # all_chelt = self.get_one_time_transactions(all_chelt)

        chelt_in_time_interval = self.filter_dates(all_chelt, selectedStartDate, selectedEndDate)
        # for chelt in chelt_in_time_interval:
        #     #print(chelt.category, chelt.name, chelt.id, chelt.pay_day, chelt.myconto, chelt.payments_for_interval)

        chelt_after_contofilter = self.filter_conto(chelt_in_time_interval, conto, hideintercontotrans)
        # for chelt in chelt_after_contofilter:
        #     #print(chelt.name, chelt.id, chelt.pay_day, chelt.myconto, chelt.payments_for_interval)

        self.expenses, self.income = self.split_expenses_income(chelt_after_contofilter)
        if self.expenses.shape == (1, 0):
            expenses = np.empty((0, len(self.tableHead)))
        if self.income.shape == (1, 0):
            income = np.empty((0, len(self.tableHead)))

    # prepareTablePlan##################################################################################

    # transactions##################################################################################
    def add_one_time_transactions(self, name, value, myconto, pay_day, id_users):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        cols = (
            'id_users', 'category', 'name', 'value', 'myconto', 'freq', 'pay_day', 'valid_from', 'valid_to', 'auto_ext')
        payday = pay_day.day
        valid_from = pay_day
        valid_to = pay_day
        vals = (id_users, 'one_time_transactions', name, value, myconto, 999, payday, valid_from, valid_to, 0)
        self.chelt_plan.addNewRow(cols, vals)

    def copy_chelt_plan_row(self, row_id):
        match = ('id', row_id)
        row = self.chelt_plan.returnRowsWhere(match)[0]
        for i, (col_name, col_type) in enumerate(self.chelt_plan.columnsProperties.items()):
            print(col_name, col_type, row[i])

    def add_transactions(self, category, name, value, myconto, freq, pay_day, valid_from, valid_to, auto_ext,
                         identification=None, cancel_auto_ext=False, id_users=1):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        cols = (
            'id_users', 'category', 'name', 'value', 'myconto', 'freq', 'pay_day', 'valid_from', 'valid_to', 'auto_ext',
            'identification')
        # payday = pay_day.day
        # valid_from = pay_day
        # valid_to = pay_day
        if valid_to == '':
            valid_to = None
        vals = (id_users, category, name, value, myconto, freq, pay_day, valid_from, valid_to, auto_ext, identification)
        new_row_id = self.chelt_plan.addNewRow(cols, vals)

        # self.chelt_plan
        if cancel_auto_ext:
            self.chelt_plan.changeCellContent('auto_ext', 0, 'id', cancel_auto_ext)
            vd = datetime.strptime(valid_from, '%Y-%m-%d')
            lastDay = vd - timedelta(days=1)
            self.chelt_plan.changeCellContent('valid_to', lastDay, 'id', cancel_auto_ext)

        return new_row_id

    def delete_transaction(self, row_id):
        if isinstance(row_id, str):
            row_id = int(row_id)
        condition = ('id', row_id)
        self.chelt_plan.delete_multiple_rows(condition)

    # transactions##################################################################################

    # write_sql_yearly##################################################################################
    def write_sql_yearly_plan(self, year=None):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if not year:
            year = datetime.now().year
        months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
        cols = ['id_users', 'db_update', 'myconto', 'expenses', 'January', 'February', 'March', 'April', 'May', 'June',
                'July', 'August', 'September', 'October', 'November', 'December']
        # vals = [1, ]
        rows_no = (len(self.myContos) + 1) * 3
        newTableData = np.empty([rows_no, len(cols)], dtype=object)
        newTableData[:, 0] = self.id_users
        newTableData[:, 1] = year
        indx_col_myconto = cols.index('myconto')
        indx_col_expenses = cols.index('expenses')
        for month in months:
            # print(month)
            col = cols.index(month)
            all_contos_monthly_tot_val_of_expenses = 0
            all_contos_monthly_tot_val_of_monthly_expenses = 0
            all_contos_monthly_tot_val_of_irregular_expenses = 0
            row_no = 0
            for currentConto in self.myContos:
                # print('\t', currentConto)
                selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
                self.prepareTablePlan(currentConto, selectedStartDate, selectedEndDate, hideintercontotrans=True)
                # print('\t\t', 'tot_val_of_expeYnses', self.tot_val_of_expenses)
                newTableData[row_no, indx_col_myconto] = currentConto
                newTableData[row_no, indx_col_expenses] = 'monthly+irregular'
                newTableData[row_no, col] = float(self.tot_val_of_expenses)
                row_no += 1
                # print('\t\t', 'tot_val_of_monthly_expenses', self.tot_val_of_monthly_expenses)
                newTableData[row_no, indx_col_myconto] = currentConto
                newTableData[row_no, indx_col_expenses] = 'monthly'
                newTableData[row_no, col] = float(self.tot_val_of_monthly_expenses)
                row_no += 1
                # print('\t\t', 'tot_val_of_irregular_expenses', self.tot_val_of_irregular_expenses)
                newTableData[row_no, indx_col_myconto] = currentConto
                newTableData[row_no, indx_col_expenses] = 'irregular'
                newTableData[row_no, col] = float(self.tot_val_of_irregular_expenses)
                row_no += 1

                all_contos_monthly_tot_val_of_expenses += self.tot_val_of_expenses
                all_contos_monthly_tot_val_of_monthly_expenses += self.tot_val_of_monthly_expenses
                all_contos_monthly_tot_val_of_irregular_expenses += self.tot_val_of_irregular_expenses
            # print('\t', 'all')
            # print('\t\t', 'tot_val_of_expenses', all_contos_monthly_tot_val_of_expenses)
            newTableData[row_no, indx_col_myconto] = 'all'
            newTableData[row_no, indx_col_expenses] = 'monthly+irregular'
            newTableData[row_no, col] = float(all_contos_monthly_tot_val_of_expenses)
            row_no += 1
            # print('\t\t', 'tot_val_of_monthly_expenses', all_contos_monthly_tot_val_of_monthly_expenses)
            newTableData[row_no, indx_col_myconto] = 'all'
            newTableData[row_no, indx_col_expenses] = 'monthly'
            newTableData[row_no, col] = float(all_contos_monthly_tot_val_of_monthly_expenses)
            row_no += 1

            # print('\t\t', 'tot_val_of_irregular_expenses', all_contos_monthly_tot_val_of_irregular_expenses)
            newTableData[row_no, indx_col_myconto] = 'all'
            newTableData[row_no, indx_col_expenses] = 'irregular'
            newTableData[row_no, col] = float(all_contos_monthly_tot_val_of_irregular_expenses)
            row_no += 1
        for rw in newTableData:
            # print('#####rw', rw)
            myconto, chelt_type = rw[2], rw[3]
            matches = [('id_users', '=', self.id_users),
                       ('myconto', '=', myconto),
                       ('expenses', '=', chelt_type),
                       ('db_update', '=', year),
                       ]
            # print('write_sql_yearly_plan_matches****', matches)
            rows = self.yearly_plan.returnRowsQuery(matches)
            if rows:
                # for row in rows:
                print('already existing:', rows)
                if len(rows) > 1:
                    raise RuntimeError('We have a problem')
                else:
                    existing_row = rows[0]
                    rid = existing_row[0]
                    for cc in range(4, 16):
                        # print('cols[cc], row[cc]', cols[cc], rw[cc])
                        self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)

            else:
                self.yearly_plan.addNewRow(cols, tuple(rw))
        print('Finish to write/update yearly_plan')
        return newTableData

    # def write_sql_yearly_all_old(self, year=None):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
    #     cols = ['id_users', 'db_update', 'expenses', 'myconto', 'January', 'February', 'March', 'April', 'May', 'June',
    #             'July', 'August', 'September', 'October', 'November', 'December']
    #     # vals = [1, ]
    #     rows_no = (len(self.myContos) + 1)
    #     newTableData = np.empty([rows_no, len(cols)], dtype=object)
    #     newTableData[:, 0] = self.id_users
    #     newTableData[:, 1] = year
    #     newTableData[:, 2] = 'planned_expenses'
    #     indx_col_myconto = cols.index('myconto')
    #     indx_col_expenses = cols.index('expenses')
    #     for month in months:
    #         # print(month)
    #         col = cols.index(month)
    #         all_contos_monthly_tot_val_of_expenses = 0
    #         row_no = 0
    #         for currentConto in self.myContos:
    #             # print('\t', currentConto)
    #             selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
    #             self.prepareTablePlan(currentConto, selectedStartDate, selectedEndDate, hideintercontotrans=True)
    #             # print('\t\t', 'tot_val_of_expeYnses', self.tot_val_of_expenses)
    #             newTableData[row_no, indx_col_myconto] = currentConto
    #             newTableData[row_no, col] = float(self.tot_val_of_expenses)
    #             row_no += 1
    #             all_contos_monthly_tot_val_of_expenses += self.tot_val_of_expenses
    #         # print('\t', 'all')
    #         # print('\t\t', 'tot_val_of_expenses', all_contos_monthly_tot_val_of_expenses)
    #         newTableData[row_no, indx_col_myconto] = 'all'
    #         newTableData[row_no, indx_col_expenses] = 'planned_expenses'
    #         newTableData[row_no, col] = float(all_contos_monthly_tot_val_of_expenses)
    #         row_no += 1
    #
    #     for rw in newTableData:
    #         # print(rw)
    #         # continue2
    #         myconto, chelt_type = rw[3], rw[2]
    #         matches = [('id_users', '=', self.id_users),
    #                    ('myconto', '=', myconto),
    #                    ('expenses', '=', chelt_type),
    #                    ('db_update', '=', year),
    #                    ]
    #         rows = self.yearly_all.returnRowsQuery(matches)
    #         if rows:
    #             print('already existing:', rows)
    #             if len(rows) > 1:
    #                 raise RuntimeError('We have a problem')
    #             else:
    #                 existing_row = rows[0]
    #                 rid = existing_row[0]
    #                 for cc in range(4, 16):
    #                     # print('cols[cc], row[cc]', cols[cc], rw[cc])
    #                     self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
    #         else:
    #             self.yearly_all.addNewRow(cols, tuple(rw))
    #     print('Finish to write/update yearly_all')
    #     return newTableData

    # def write_sql_yearly_all(self, year=None, write_to_sql=True):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
    #     cols = ('id_users', 'db_update', 'expenses', 'myconto', 'category', 'January', 'February',
    #             'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
    #     index_january = cols.index('January')
    #     # rows_no = (len(self.myContos) + 1)
    #     self.prepareTablePlan('all', datetime(year, 1, 1).date(), datetime(year, 12, 31).date(),
    #                           hideintercontotrans=False)
    #     all_banks = list(self.expenses_per_conto_per_category.keys())
    #     tv, ttrno, dict_all_categories = self.expenses_per_conto_per_category['all']
    #     all_catgories_per_year = list(dict_all_categories.keys())
    #     # all_catgories_per_year = self.categories
    #
    #     rows_no = len(all_banks) * len(all_catgories_per_year) + len(all_banks)
    #     newTableData = np.empty([rows_no, len(cols)], dtype=object)
    #     newTableData[:, cols.index('id_users')] = self.id_users
    #     newTableData[:, cols.index('db_update')] = year
    #     newTableData[:, cols.index('expenses')] = 'planned_expenses'
    #     indx_col_myconto = cols.index('myconto')
    #     indx_col_category = cols.index('category')
    #     for month in months:
    #         print(month)
    #         col = cols.index(month)
    #         all_contos_monthly_tot_val_of_expenses = 0
    #         row_no = 0
    #         selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
    #         self.prepareTablePlan('all', selectedStartDate, selectedEndDate, hideintercontotrans=False)
    #         if self.expenses_per_conto_per_category:
    #             for currentConto in all_banks:
    #                 if currentConto in self.expenses_per_conto_per_category.keys():
    #                     tot_val_per_conto_per_month, tot_trans_per_conto_per_month, dict_all_categories_per_month = \
    #                         self.expenses_per_conto_per_category[currentConto]
    #                     newTableData[row_no, indx_col_myconto] = currentConto
    #                     newTableData[row_no, indx_col_category] = 'all'
    #                     newTableData[row_no, col] = tot_val_per_conto_per_month
    #                     row_no += 1
    #                     for cat in all_catgories_per_year:
    #                         if cat in dict_all_categories_per_month.keys():
    #                             value, noofranspermont = dict_all_categories_per_month[cat]
    #                             value = float(value)
    #                             # print('currentConto, cat, value', currentConto, cat, value)
    #                             # sys.exit()
    #                             newTableData[row_no, indx_col_myconto] = currentConto
    #                             newTableData[row_no, indx_col_category] = cat
    #                             newTableData[row_no, col] = value
    #                             row_no += 1
    #                         else:
    #                             newTableData[row_no, indx_col_myconto] = currentConto
    #                             newTableData[row_no, indx_col_category] = cat
    #                             newTableData[row_no, col] = None
    #                             row_no += 1
    #                 else:
    #                     newTableData[row_no, indx_col_myconto] = currentConto
    #                     newTableData[row_no, indx_col_category] = 'all'
    #                     newTableData[row_no, col] = None
    #                     row_no += 1
    #                     for cat in all_catgories_per_year:
    #                         newTableData[row_no, indx_col_myconto] = currentConto
    #                         newTableData[row_no, indx_col_category] = cat
    #                         newTableData[row_no, col] = None
    #                         # print('\tcurrentConto, value', currentConto, value)
    #                         row_no += 1
    #
    #     for rw in newTableData:
    #         print('äääärw', rw)
    #         if not write_to_sql:
    #             continue
    #         myconto, chelt_type, category = rw[indx_col_myconto], rw[2], rw[indx_col_category]
    #         matches = [('id_users', '=', self.id_users),
    #                    ('db_update', '=', year),
    #                    ('expenses', '=', chelt_type),
    #                    ('myconto', '=', myconto),
    #                    ('category', '=', category),
    #                    ]
    #         rows = self.yearly_all.returnRowsQuery(matches)
    #         if rows:
    #             print('already existing:', rows)
    #             if len(rows) > 1:
    #                 raise RuntimeError('We have a problem')
    #             else:
    #                 existing_row = rows[0]
    #                 rid = existing_row[0]
    #                 for cc in range(index_january, len(cols)):
    #                     # print('cols[cc], row[cc]', cols[cc], rw[cc])
    #                     self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
    #         else:
    #             self.yearly_all.addNewRow(cols, tuple(rw))
    #     print('Finish to write/update yearly_all')
    #     return newTableData

    def write_planned_expenses_yearly_all(self, year=None, write_to_sql=True):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if not year:
            year = datetime.now().year
        months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
        cols = ('id_users', 'db_update', 'expenses', 'myconto', 'category', 'January', 'February',
                'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
        index_january = cols.index('January')
        # rows_no = (len(self.myContos) + 1)
        self.prepareTablePlan('all', datetime(year, 1, 1).date(), datetime(year, 12, 31).date(),
                              hideintercontotrans=False)
        all_banks = list(self.expenses_per_conto_per_category.keys())
        tv, ttrno, dict_all_categories = self.expenses_per_conto_per_category['all']
        all_catgories_per_year = list(dict_all_categories.keys())
        # all_catgories_per_year = self.categories

        rows_no = len(all_banks) * len(all_catgories_per_year) + len(all_banks)
        newTableData = np.empty([rows_no, len(cols)], dtype=object)
        newTableData[:, cols.index('id_users')] = self.id_users
        newTableData[:, cols.index('db_update')] = year
        newTableData[:, cols.index('expenses')] = 'planned_expenses'
        indx_col_myconto = cols.index('myconto')
        indx_col_category = cols.index('category')
        for month in months:
            print(month)
            col = cols.index(month)
            all_contos_monthly_tot_val_of_expenses = 0
            row_no = 0
            selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
            self.prepareTablePlan('all', selectedStartDate, selectedEndDate, hideintercontotrans=False)
            if self.expenses_per_conto_per_category:
                for currentConto in all_banks:
                    if currentConto in self.expenses_per_conto_per_category.keys():
                        tot_val_per_conto_per_month, tot_trans_per_conto_per_month, dict_all_categories_per_month = \
                            self.expenses_per_conto_per_category[currentConto]
                        newTableData[row_no, indx_col_myconto] = currentConto
                        newTableData[row_no, indx_col_category] = 'all'
                        newTableData[row_no, col] = tot_val_per_conto_per_month
                        row_no += 1
                        for cat in all_catgories_per_year:
                            if cat in dict_all_categories_per_month.keys():
                                value, noofranspermont = dict_all_categories_per_month[cat]
                                value = float(value)
                                # print('currentConto, cat, value', currentConto, cat, value)
                                # sys.exit()
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = value
                                row_no += 1
                            else:
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = 0
                                row_no += 1
                    else:
                        newTableData[row_no, indx_col_myconto] = currentConto
                        newTableData[row_no, indx_col_category] = 'all'
                        newTableData[row_no, col] = 0
                        row_no += 1
                        for cat in all_catgories_per_year:
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = cat
                            newTableData[row_no, col] = 0
                            # print('\tcurrentConto, value', currentConto, value)
                            row_no += 1

        for rw in newTableData:
            print('äääärw', rw)
            if not write_to_sql:
                continue
            myconto, chelt_type, category = rw[indx_col_myconto], rw[2], rw[indx_col_category]
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', year),
                       ('expenses', '=', chelt_type),
                       ('myconto', '=', myconto),
                       ('category', '=', category),
                       ]
            rows = self.yearly_all.returnRowsQuery(matches)
            if rows:
                print('already existing:', rows)
                if len(rows) > 1:
                    raise RuntimeError('We have a problem')
                else:
                    existing_row = rows[0]
                    rid = existing_row[0]
                    for cc in range(index_january, len(cols)):
                        # print('cols[cc], row[cc]', cols[cc], rw[cc])
                        self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
            else:
                self.yearly_all.addNewRow(cols, tuple(rw))
        print('Finish to write/update yearly_all')
        return newTableData

    def write_planned_income_yearly_all(self, year=None, write_to_sql=True):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if not year:
            year = datetime.now().year
        months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
        cols = ('id_users', 'db_update', 'expenses', 'myconto', 'category', 'January', 'February',
                'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
        index_january = cols.index('January')
        # rows_no = (len(self.myContos) + 1)
        self.prepareTablePlan('all', datetime(year, 1, 1).date(), datetime(year, 12, 31).date(),
                              hideintercontotrans=False)
        all_banks = list(self.income_per_conto_per_category.keys())
        tv, ttrno, dict_all_categories = self.income_per_conto_per_category['all']
        all_catgories_per_year = list(dict_all_categories.keys())
        # all_catgories_per_year = self.categories

        rows_no = len(all_banks) * len(all_catgories_per_year) + len(all_banks)
        newTableData = np.empty([rows_no, len(cols)], dtype=object)
        newTableData[:, cols.index('id_users')] = self.id_users
        newTableData[:, cols.index('db_update')] = year
        newTableData[:, cols.index('expenses')] = 'planned_income'
        indx_col_myconto = cols.index('myconto')
        indx_col_category = cols.index('category')
        for month in months:
            print(month)
            col = cols.index(month)
            all_contos_monthly_tot_val_of_expenses = 0
            row_no = 0
            selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
            self.prepareTablePlan('all', selectedStartDate, selectedEndDate, hideintercontotrans=False)
            if self.income_per_conto_per_category:
                for currentConto in all_banks:
                    if currentConto in self.income_per_conto_per_category.keys():
                        tot_val_per_conto_per_month, tot_trans_per_conto_per_month, dict_all_categories_per_month = \
                            self.income_per_conto_per_category[currentConto]
                        newTableData[row_no, indx_col_myconto] = currentConto
                        newTableData[row_no, indx_col_category] = 'all'
                        newTableData[row_no, col] = tot_val_per_conto_per_month
                        row_no += 1
                        for cat in all_catgories_per_year:
                            if cat in dict_all_categories_per_month.keys():
                                value, noofranspermont = dict_all_categories_per_month[cat]
                                value = float(value)
                                # print('currentConto, cat, value', currentConto, cat, value)
                                # sys.exit()
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = value
                                row_no += 1
                            else:
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = 0
                                row_no += 1
                    else:
                        newTableData[row_no, indx_col_myconto] = currentConto
                        newTableData[row_no, indx_col_category] = 'all'
                        newTableData[row_no, col] = 0
                        row_no += 1
                        for cat in all_catgories_per_year:
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = cat
                            newTableData[row_no, col] = 0
                            # print('\tcurrentConto, value', currentConto, value)
                            row_no += 1

        for rw in newTableData:
            print('äääärw', rw)
            if not write_to_sql:
                continue
            myconto, chelt_type, category = rw[indx_col_myconto], rw[2], rw[indx_col_category]
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', year),
                       ('expenses', '=', chelt_type),
                       ('myconto', '=', myconto),
                       ('category', '=', category),
                       ]
            rows = self.yearly_all.returnRowsQuery(matches)
            if rows:
                print('already existing:', rows)
                if len(rows) > 1:
                    raise RuntimeError('We have a problem')
                else:
                    existing_row = rows[0]
                    rid = existing_row[0]
                    for cc in range(index_january, len(cols)):
                        # print('cols[cc], row[cc]', cols[cc], rw[cc])
                        self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
            else:
                self.yearly_all.addNewRow(cols, tuple(rw))
        print('Finish to write/update yearly_all')
        return newTableData

    # write_sql_yearly##################################################################################

    # 4plots##################################################################################
    def prep_yearly_graf(self, year=None):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if not year:
            year = datetime.now().year
        matches = [('id_users', '=', self.id_users),
                   ('db_update', '=', year),
                   ('myconto', '=', 'all')
                   ]
        payments4Interval = self.yearly_plan.returnRowsQuery(matches)
        labels = self.yearly_plan.columnsNames[6:]
        payments_dict = {}
        for row in payments4Interval:
            # print('KKKKKrow', row)
            chelt_type = row[5]
            vals = []
            for val in row[6:]:
                vals.append(float(val))
            payments_dict[chelt_type] = vals
        return payments_dict, labels

    # def prep_conto_yearly_graf(self, year=None):
    #     # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     matches = [('id_users', '=', self.id_users),
    #                ('db_update', '=', year),
    #                ('expenses', '=', 'planned_expenses'),
    #                ('category', '=', 'all')
    #                ]
    #     payments4Interval = self.yearly_all.returnRowsQuery(matches)
    #     index_january = self.yearly_all.columnsNames.index('January')
    #     labels = self.yearly_all.columnsNames[index_january:]
    #     payments_dict = {}
    #     for row in payments4Interval:
    #         # print('row****', row)
    #         my_conto = row[self.yearly_all.columnsNames.index('myconto')]
    #         # if my_conto == 'all':
    #         #     continue
    #         vals = []
    #         for val in row[index_january:]:
    #             if val is None:
    #                 vals.append(val)
    #                 continue
    #             vals.append(float(val))
    #         payments_dict[my_conto] = vals
    #     return payments_dict, labels

    def category_values4pie(self):
        total_monthly_values = self.expenses_per_category['all']
        total_monthly_values = total_monthly_values[0]
        pielabels = []
        piesizes = []

        for myConto, yearly_list in self.expenses_per_category.items():
            if myConto == 'all':
                continue
            # print('myConto::planned_payments_dict, yearly_list, ', myConto, yearly_list, )
            value = yearly_list[0]
            txt = '{} = {:.2f}'.format(myConto, value)
            pielabels.append(txt)
            size = (value / total_monthly_values) * 100
            piesizes.append(size)
        return piesizes, pielabels, total_monthly_values

    def name_values4pie(self):
        total_monthly_values = self.expenses_per_names['all']
        total_monthly_values = total_monthly_values[0]
        pielabels = []
        piesizes = []

        for myConto, yearly_list in self.expenses_per_names.items():
            if myConto == 'all':
                continue
            # print('myConto::planned_payments_dict, yearly_list, ', myConto, yearly_list, )
            value = yearly_list[0]
            txt = '{} = {:.2f}'.format(myConto, value)
            pielabels.append(txt)
            size = (value / total_monthly_values) * 100
            piesizes.append(size)
        return piesizes, pielabels, total_monthly_values


class CheltuieliReale:
    def __init__(self, chelt_db, myAccountsTable, imported_csv, chelt_plan, knowntrans, plan_vs_real, sskm, deubnk, n26,
                 yearly_all, id_users):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        self.displayRealTableHead = ['myconto', 'category', 'name', 'plannedvalue', 'Buchungstag',
                                     'Betrag', 'PaymentReference',
                                     'PartnerName']  # , 'Buchungstext', 'Beguenstigter', 'Verwendungszweck']
        self.myAccountsTable = myAccountsTable
        self.imported_csv = imported_csv
        self.chelt_plan = chelt_plan
        self.knowntrans = knowntrans
        self.plan_vs_real = plan_vs_real
        self.sskm = sskm
        self.deubnk = deubnk
        self.n26 = n26
        self.yearly_all = yearly_all
        self.id_users = id_users
        self.realExpenses = None
        self.realIncome = None

        try:
            self.dataBase = chelt_db
        except Exception as err:
            print(traceback.format_exc())
        CheckCheltRequiredFiles(self.dataBase, self.myAccountsTable, self.imported_csv, self.chelt_plan,
                                self.knowntrans, self.plan_vs_real, self.sskm, self.deubnk, self.n26, )

    @property
    def sql_rm(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}'.format(__name__, __class__, sys._getframe().f_code.co_name))
        if self.conf.db_type == 'mysql':
            sql_rm = mysql_rm
        return sql_rm

    @property
    def myContos(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        return list(set(self.yearly_all.returnColumn('myconto')))

    @property
    def categories(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        all_cat = list(set(self.yearly_all.returnColumn('category')))
        # all_cat = [s.lower() for s in all_cat if s is not None]
        return all_cat

    @property
    def imported_csv_dates(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        buchungs_min_max = {}
        # if contos == 'all':
        all_contos = list(set(self.imported_csv.returnColumn('banca')))
        # if specific_conto:
        #     all_contos =[specific_conto]
        for con in all_contos:
            # print(con)
            min, max = self.get_buchungstag_interval(con)
            buchungs_min_max[con] = [min, max]
        return buchungs_min_max

    @property
    def banks(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        all_banks = list(set(self.myAccountsTable.returnColumn('banca')))
        return all_banks

    @property
    def table_head(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        return self.plan_vs_real.columnsNames

    @property
    def tot_val_of_expenses(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        if self.realExpenses.shape == (1, 0):
            return None
        allValues = self.realExpenses[:, self.table_head.index('Betrag')]
        if None in allValues:
            allValues = allValues[allValues != np.array(None)]

        totalVal = round(sum(allValues.astype(float)), 2)
        return totalVal

    @property
    def tot_val_of_income(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        if self.realIncome.shape == (1, 0):
            return None
        allValues = self.realIncome[:, self.table_head.index('Betrag')]
        if None in allValues:
            allValues = allValues[allValues != np.array(None)]

        totalVal = round(sum(allValues.astype(float)), 2)
        return totalVal

    @property
    def tot_no_of_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # allValues = self.expenses[:, self.tableHead.index('value')]
        # if None in allValues:
        #     allValues = allValues[allValues != np.array(None)]
        return self.realExpenses.shape[0]

    @property
    def expenses_per_conto(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realExpenses.shape == (1, 0):
            return None
        contos = np.unique(self.realExpenses[:, self.table_head.index('myconto')])
        total_amount = 0
        total_transactions = 0
        # for con in contos:
        for con in self.myContos:
            conto_arr = self.realExpenses[self.realExpenses[:, self.table_head.index('myconto')] == con]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[con] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    @property
    def expenses_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realExpenses.shape == (1, 0):
            return None
        # categories = list(set(self.realExpenses[:, self.table_head.index('category')]))
        total_amount = 0
        total_transactions = 0
        for cat in self.categories:
            # if cat is None:
            #     cat = 'None'
            conto_arr = self.realExpenses[self.realExpenses[:, self.table_head.index('category')] == cat]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    @property
    def income_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realIncome.shape == (1, 0):
            return None
        categories = list(set(self.realIncome[:, self.table_head.index('category')]))
        total_amount = 0
        total_transactions = 0
        for cat in categories:
            # if cat is None:
            #     cat = 'None'
            conto_arr = self.realIncome[self.realIncome[:, self.table_head.index('category')] == cat]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    @property
    def expenses_per_conto_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realExpenses.shape == (1, 0):
            return None
        contos = np.unique(self.realExpenses[:, self.table_head.index('myconto')])
        total_amount = 0
        total_transactions = 0
        per_category_only = {}
        for con in contos:
            # print('+++con', con)
            conto_arr = self.realExpenses[self.realExpenses[:, self.table_head.index('myconto')] == con]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            # print('(tot_val, no_of_transactions)', (tot_val, no_of_transactions))

            # print('conto_arr', conto_arr)
            # print('conto_arr.shape', conto_arr.shape)
            # sys.exit()
            totals_per_category = {}
            categories = list(set(conto_arr[:, self.table_head.index('category')]))
            # total_cat_amount = 0
            # total_cat_transactions = 0
            for cat in categories:
                # print('\t+++cat', cat)
                # if cat is None:
                #     cat = 'None'
                cat_arr = conto_arr[conto_arr[:, self.table_head.index('category')] == cat]
                col = cat_arr[:, self.table_head.index('Betrag')]
                tot_cat_val = sum(col)
                no_of_cat_transactions = len(col)
                totals_per_category[cat] = (tot_cat_val, no_of_cat_transactions)
                if cat in per_category_only.keys():
                    pc_tot_val, pc_to_no_of_transactions = per_category_only[cat]
                    pc_tot_val += tot_cat_val
                    pc_to_no_of_transactions += no_of_cat_transactions
                    per_category_only[cat] = (pc_tot_val, pc_to_no_of_transactions)
                else:
                    per_category_only[cat] = (tot_cat_val, no_of_cat_transactions)
            totals_per_conto[con] = (tot_val, no_of_transactions, totals_per_category)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions, per_category_only)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    @property
    def expenses_per_name(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realExpenses.shape == (1, 0):
            return None
        categories = list(set(self.realExpenses[:, self.table_head.index('name')]))
        total_amount = 0
        total_transactions = 0
        for cat in categories:
            # if cat is None:
            #     cat = 'None'
            conto_arr = self.realExpenses[self.realExpenses[:, self.table_head.index('name')] == cat]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[cat] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    @property
    def total_income_minus_expenses_per_conto(self):
        totals_per_conto = {}
        contos = np.unique(self.realExpenses[:, self.table_head.index('myconto')])
        total_amount = 0
        total_transactions = 0
        for con in contos:
            conto_arr_expenses = self.realExpenses[self.realExpenses[:, self.table_head.index('myconto')] == con]
            col_expenses = conto_arr_expenses[:, self.table_head.index('Betrag')]
            tot_val_expenses = sum(col_expenses)
            no_of_transactions_expenses = len(col_expenses)

            if self.realIncome.shape[1] > 0:
                conto_arr_income = self.realIncome[self.realIncome[:, self.table_head.index('myconto')] == con]
                col_income = conto_arr_income[:, self.table_head.index('Betrag')]
                tot_val_income = sum(col_income)
                no_of_transactions_income = len(col_income)
            else:
                tot_val_income = 0
                no_of_transactions_income = 0

            tot_val = tot_val_expenses + tot_val_income
            no_of_transactions = no_of_transactions_expenses + no_of_transactions_income

            totals_per_conto[con] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['total'] = (total_amount, total_transactions)
        return totals_per_conto

    @property
    def income_per_conto(self):
        totals_per_conto = {}
        # print('JJJJJJself.realIncome', self.realIncome, type(self.realIncome), self.realIncome.shape)
        if self.realIncome.shape == (1, 0):
            return None
        contos = np.unique(self.realIncome[:, self.table_head.index('myconto')])
        total_amount = 0
        total_transactions = 0
        for con in contos:
            conto_arr = self.realIncome[self.realIncome[:, self.table_head.index('myconto')] == con]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            totals_per_conto[con] = (tot_val, no_of_transactions)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions)
        return totals_per_conto

    @property
    def income_per_conto_per_category(self):
        totals_per_conto = {}
        # print('++self.realExpenses.shape', self.realExpenses.shape)
        if self.realIncome.shape == (1, 0):
            return None
        contos = np.unique(self.realIncome[:, self.table_head.index('myconto')])  # todo aici am ramas
        total_amount = 0
        total_transactions = 0
        per_category_only = {}
        for con in contos:
            # print('+++con', con)
            conto_arr = self.realIncome[self.realIncome[:, self.table_head.index('myconto')] == con]
            col = conto_arr[:, self.table_head.index('Betrag')]
            tot_val = sum(col)
            no_of_transactions = len(col)
            # print('(tot_val, no_of_transactions)', (tot_val, no_of_transactions))

            # print('conto_arr', conto_arr)
            # print('conto_arr.shape', conto_arr.shape)
            # sys.exit()
            totals_per_category = {}
            categories = list(set(conto_arr[:, self.table_head.index('category')]))
            # total_cat_amount = 0
            # total_cat_transactions = 0
            for cat in categories:
                # print('\t+++cat', cat)
                # if cat is None:
                #     cat = 'None'
                cat_arr = conto_arr[conto_arr[:, self.table_head.index('category')] == cat]
                col = cat_arr[:, self.table_head.index('Betrag')]
                tot_cat_val = sum(col)
                no_of_cat_transactions = len(col)
                totals_per_category[cat] = (tot_cat_val, no_of_cat_transactions)
                if cat in per_category_only.keys():
                    pc_tot_val, pc_to_no_of_transactions = per_category_only[cat]
                    pc_tot_val += tot_cat_val
                    pc_to_no_of_transactions += no_of_cat_transactions
                    per_category_only[cat] = (pc_tot_val, pc_to_no_of_transactions)
                else:
                    per_category_only[cat] = (tot_cat_val, no_of_cat_transactions)
            totals_per_conto[con] = (tot_val, no_of_transactions, totals_per_category)
            total_amount += tot_val
            total_transactions += no_of_transactions
        totals_per_conto['all'] = (total_amount, total_transactions, per_category_only)
        # totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: item[0]))
        totals_per_conto = dict(sorted(totals_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return totals_per_conto

    def get_bank(self, currentConto):
        matches = [('name', currentConto), ('id_users', self.id_users)]
        # print('matches**', matches)
        banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]
        return banca

    def default_interval(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        # startDate = datetime(datetime.now().year - 1, datetime.now().month, datetime.now().day)
        startDate = datetime(datetime.now().year - 1, datetime.now().month, 1)
        if datetime.now().month != 12:
            mnth = datetime.now().month + 1
            lastDayOfMonth = datetime(datetime.now().year - 1, mnth, 1) - timedelta(days=1)
        else:
            lastDayOfMonth = datetime(datetime.now().year, 1, 1) - timedelta(days=1)
        return startDate, lastDayOfMonth

    def last_month_of_last_csv(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        latest_date = None
        for bnk, interval in self.imported_csv_dates.items():
            start, end = interval
            # print(end.month)
            if not latest_date:
                latest_date = end
            else:
                latest_date = max(latest_date, end)
        month = convert_months(latest_date.month)
        startDate, lastDayOfMonth = get_monthly_interval(month, latest_date.year)
        return startDate, lastDayOfMonth

    def get_buchungstag_interval(self, currentConto):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        if currentConto != 'all':
            matches = ('banca', currentConto)
            # #print(currentConto)
            start_col = self.imported_csv.returnCellsWhere('start', matches)
            end_col = self.imported_csv.returnCellsWhere('end', matches)
            # #print(start_col)
        else:
            start_col = self.imported_csv.returnColumn('start')
            end_col = self.imported_csv.returnColumn('end')

        # #print(100*'allbuchungstag')
        # #print(allbuchungstag)
        if start_col and end_col:
            return min(start_col), max(end_col)
        else:
            return None, None

    # def add_row_to_imported_csv(self, inpFile, banca, start, end, total_rows, imported_rows):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     cols = ['id_users', 'file_name', 'banca', 'start', 'end', 'file', 'total_rows', 'imported_rows']
    #     path, file_name = os.path.split(inpFile)
    #     vals = [self.id_users, file_name, banca, start, end, inpFile, total_rows, imported_rows]
    #     self.imported_csv.addNewRow(cols, tuple(vals))

    def check_csv_table_head(self, inpFile, bank):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        sql_table_head = None
        csv_tabel_cheltuieli = []
        if bank == 'DeutscheBank':
            delimiter = ';'
            encoding = 'unicode_escape'
            table_head_indx = None
            with open(inpFile, 'r', encoding=encoding, newline='') as csvfile:
                linereader = csv.reader(csvfile, delimiter=delimiter, quotechar='"')
                for i, row in enumerate(linereader):
                    if row and (row[0] == 'Booking date' or row[0] == 'Buchungstag'):
                        table_head_indx = i
                        len_table_head = len(row)
                        break
        elif bank == 'Stadtsparkasse München':
            delimiter = ';'
            encoding = 'unicode_escape'
            with open(inpFile, 'r', encoding=encoding, newline='') as csvfile:
                linereader = csv.reader(csvfile, delimiter=delimiter, quotechar='"')
                for i, row in enumerate(linereader):
                    if row and row[0] == 'Auftragskonto':
                        table_head_indx = i
                        len_table_head = len(row)
                        break
        elif bank == 'N26':
            delimiter = ','
            encoding = 'utf8'
            with open(inpFile, 'r', encoding=encoding, newline='') as csvfile:
                linereader = csv.reader(csvfile, delimiter=delimiter, quotechar='"')
                for i, row in enumerate(linereader):
                    print('N25 row', row, row[0] == 'Date')
                    if row and (row[0].lower() == 'booking date' or row[0] == 'Date'):
                        print('tab++++')
                        table_head_indx = i
                        len_table_head = len(row)
                        break

        with open(inpFile, 'r', encoding=encoding, newline='') as csvfile:
            linereader = csv.reader(csvfile, delimiter=delimiter, quotechar='"')
            for i, row in enumerate(linereader):
                # if i == 0 and bank != 'DeutscheBank':
                #     # #print('####', row)
                #     csv_table_head = row
                #     tabHeadDict = bank_tabHeadDict[bank]
                #     # #print('AAAAAAAAAA', tabHeadDict)
                #     known_table_head = (list(tabHeadDict.keys()))
                #     all_csv_cols_in_known_table_head = all(item in known_table_head for item in csv_table_head)
                #     # #print('all_csv_cols_in_known_table_head', all_csv_cols_in_known_table_head)
                #     all_known_table_head_cols_in_csv = all(item in csv_table_head for item in known_table_head)
                #     # #print('all_known_table_head_cols_in_csv', all_known_table_head_cols_in_csv)
                #     if all_csv_cols_in_known_table_head and all_known_table_head_cols_in_csv:
                #         sql_table_head = list(tabHeadDict.values())
                # elif i > 0 and bank != 'DeutscheBank':
                #     csv_tabel_cheltuieli.append(row)
                if i < table_head_indx:  # and bank == 'DeutscheBank'
                    continue
                elif i == table_head_indx:  # and bank == 'DeutscheBank'
                    # print('row###', row)
                    csv_table_head = row
                    table_head_versions_list = bank_tabHeadDict[bank]
                    for tabHeadDict in table_head_versions_list:
                        known_table_head = list(tabHeadDict.keys())
                        all_csv_cols_in_known_table_head = all(item in known_table_head for item in csv_table_head)
                        csv_cols_not_in_known_table_head = [x for x in csv_table_head if x not in known_table_head]
                        all_known_table_head_cols_in_csv = all(item in csv_table_head for item in known_table_head)
                        known_table_head_cols_not_in_csv = [x for x in known_table_head if x not in csv_table_head]
                        # print('**THknown_table_head', known_table_head)
                        # print('**csv_table_head', csv_table_head)
                        # print('**THknown_table_head', len(csv_table_head), len(known_table_head))
                        # print('**all_csv_cols_in_known_table_head', all_csv_cols_in_known_table_head)
                        # print('**csv_cols_not_in_known_table_head', csv_cols_not_in_known_table_head)
                        # print('**all_known_table_head_cols_in_csv', all_known_table_head_cols_in_csv)
                        # print('**known_table_head_cols_not_in_csv', known_table_head_cols_not_in_csv)
                        # print()
                        if all_csv_cols_in_known_table_head and all_known_table_head_cols_in_csv:
                            sql_table_head = list(tabHeadDict.values())
                            break
                elif i > table_head_indx and len(row) == len_table_head:
                    csv_tabel_cheltuieli.append(row)
        return sql_table_head, csv_tabel_cheltuieli, tabHeadDict

    def import_CSV_new(self, currentConto, inpFile, banca=None):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,sys._getframe().f_back.f_code.co_name))
        try:
            file_name = os.path.split(inpFile)[1]
            if not banca:
                matches = [('name', currentConto), ('id_users', self.id_users)]
                banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]
            matches = [('file_name', file_name), ('id_users', self.id_users)]
            ids = self.imported_csv.returnCellsWhere('id', matches)
            if ids:
                print('File {} is already imported in db'.format(file_name))
                return
        except:
            print('matches**', matches)
            raise RuntimeError('Could not find the bank for the account {}'.format(currentConto))
        table_head, csv_tabel_cheltuieli, tabHeadDict = self.check_csv_table_head(inpFile, banca)
        if not table_head:
            raise RuntimeError('CSV file table head does not match the known format: {}'.format(file_name))
        if banca == 'DeutscheBank':
            bnk_table = self.deubnk
            betragIndx = table_head.index('Debit')
            creditIndx = table_head.index('Credit')
            buchungstagIndx = table_head.index('Buchungstag')
            valutadatumIndx = table_head.index('Valuedate')
            verwendungszweckIndx = table_head.index('Verwendungszweck')
            ibanIndx = table_head.index('IBAN')
            # print('KKKKKKtable_head', table_head, len(table_head))
            # print('KKKKKKcreditIndx', creditIndx)
            # print('KKKKKKtable_head[creditIndx]', table_head[creditIndx])
            # sys.exit()
        elif banca == 'Stadtsparkasse München':
            bnk_table = self.sskm
            betragIndx = table_head.index('Betrag')
            buchungstagIndx = table_head.index('Buchungstag')
            valutadatumIndx = table_head.index('Valutadatum')
            verwendungszweckIndx = table_head.index('Verwendungszweck')
            ibanIndx = table_head.index('IBAN')
        elif banca == 'N26':
            bnk_table = self.n26
            betragIndx = table_head.index('Amount')
            buchungstagIndx = table_head.index('Buchungstag')
            if 'ValueDate' in table_head:
                valutadatumIndx = table_head.index('ValueDate')
            else:
                valutadatumIndx = None
            verwendungszweckIndx = table_head.index('PaymentReference')
            ibanIndx = table_head.index('IBAN')
        total_transactions = 0
        inserted_transactions = 0
        not_inserted_transactions = 0
        start = None
        end = None
        if table_head:
            cols = ['id_users', 'banca', 'file', 'file_name']

            # os_inp_file = str(inpFile)
            # print('******type(os_inp_file', type(os_inp_file))
            # print('******os_inp_file', os_inp_file)
            # sys.exit()
            path, file_name = os.path.split(inpFile)
            vals = [self.id_users, currentConto, str(inpFile), file_name]
            csv_id_row_no = self.imported_csv.addNewRow(cols, tuple(vals))
            # print('MMMMMMMMcsv_id_row_no', csv_id_row_no)
            # sys.exit()

            # print('#####table_head', table_head)
            # print('#####tabHeadDict', tabHeadDict)
            table_head.append('id_users')
            table_head.append('myconto')
            table_head.append('path2inp')
            table_head.append('row_no')
            table_head.append('csv_id')
            for i, row in enumerate(csv_tabel_cheltuieli):
                # print('ÖÖÖÖÖrow', row, len(row))
                # continue
                total_transactions += 1
                row.append(self.id_users)
                row.append(currentConto)
                row.append(file_name)
                row.append(i)
                row.append(csv_id_row_no)
                ##################### modify value to float ###########################
                if banca == 'DeutscheBank' and 'Booking date' in list(tabHeadDict.keys()):
                    # modify value to float
                    valcredit = row[creditIndx]
                    # print('LLLLLLvalcredit', valcredit)
                    if valcredit != '':
                        if ',' in valcredit:
                            valcredit = valcredit.replace(",", "")
                        valcredit = float(valcredit)
                    else:
                        valcredit = 0
                    row[creditIndx] = valcredit
                    val = row[betragIndx]
                    if val != '':
                        if ',' in val:
                            val = val.replace(",", "")
                        val = float(val)
                    else:
                        val = 0
                    row[betragIndx] = val
                elif banca == 'DeutscheBank' and 'Buchungstag' in list(tabHeadDict.keys()):
                    # modify value to float
                    valcredit = row[creditIndx]
                    # print('LLLLLLvalcredit', valcredit)
                    if valcredit != '':
                        if ',' in valcredit and '.' in valcredit:
                            valcredit = valcredit.replace(".", "")
                            valcredit = valcredit.replace(",", ".")
                        elif ',' in valcredit:
                            valcredit = valcredit.replace(",", ".")
                        valcredit = float(valcredit)
                    else:
                        valcredit = 0
                    row[creditIndx] = valcredit

                    val = row[betragIndx]
                    if val != '':
                        if ',' in val and '.' in val:
                            val = val.replace(".", "")
                            val = val.replace(",", ".")
                        elif ',' in val:
                            val = val.replace(",", ".")
                        val = float(val)
                    else:
                        val = 0
                    row[betragIndx] = val
                    # print('LLLLLLval', val)
                else:
                    val = row[betragIndx]
                    # print('ÖÖÖÖÖval', val)
                    if val != '':
                        if ',' in val and '.' in val:
                            val = val.replace(",", "")
                        elif ',' in val:
                            val = val.replace(",", ".")
                        val = float(val)
                    else:
                        val = 0
                    row[betragIndx] = val

                ######################### modify date format ############################
                if valutadatumIndx:
                    if row[valutadatumIndx] == "":
                        row[valutadatumIndx] = None
                    else:
                        valueDate = self.plan_vs_real.convertDatumFormat4SQL(row[valutadatumIndx])
                        row[valutadatumIndx] = valueDate

                if banca == 'DeutscheBank' and 'Booking date' in list(tabHeadDict.keys()):
                    buchungstag = datetime.strptime(row[buchungstagIndx], '%m/%d/%Y')
                    row[buchungstagIndx] = buchungstag
                elif banca == 'DeutscheBank' and 'Buchungstag' in list(tabHeadDict.keys()):
                    # print('row[buchungstagIndx]', row[buchungstagIndx])
                    buchungstag = datetime.strptime(row[buchungstagIndx], '%d.%m.%Y')
                    row[buchungstagIndx] = buchungstag
                else:
                    buchungstag = self.plan_vs_real.convertDatumFormat4SQL(row[buchungstagIndx])
                    row[buchungstagIndx] = buchungstag
                ################################ check start / end date ##############
                if not start:
                    start = buchungstag
                else:
                    start = min(buchungstag, start)
                if not end:
                    end = buchungstag
                else:
                    end = max(buchungstag, end)
                ################################ check if already in table ##############
                verwendungszweck = row[verwendungszweckIndx]
                iban = row[ibanIndx]
                if banca == 'DeutscheBank':
                    matches = [('Buchungstag', str(buchungstag)),
                               ('Debit', val),
                               ('Credit', valcredit),
                               ('IBAN', iban),
                               ('Verwendungszweck', verwendungszweck)]
                elif banca == 'Stadtsparkasse München':
                    matches = [('Buchungstag', str(buchungstag)),
                               ('Betrag', val),
                               ('IBAN', iban),
                               ('Verwendungszweck', verwendungszweck)]
                elif banca == 'N26':
                    matches = [('Buchungstag', str(buchungstag)),
                               ('Amount', val),
                               ('IBAN', iban),
                               ('PaymentReference', verwendungszweck)]

                found_ids = bnk_table.returnCellsWhere('id', matches)
                # #print('****matches', matches)
                # #print('****found_ids', found_ids)
                # #print('****file_name', file_name)
                if found_ids:
                    other_file = False
                    for f_id in found_ids:
                        fl = bnk_table.returnCellsWhere('path2inp', ('id', f_id))[0]
                        # #print('+{}+'.format(fl), '+{}+'.format(file_name), fl != file_name)
                        # #print('++', type(fl), type(file_name), fl != file_name)
                        if fl != file_name:
                            other_file = True
                    if other_file:
                        message = 'row {} already existing at row id {}...skip'.format(row, str(found_ids))
                        not_inserted_transactions += 1
                        # print(message)
                        continue
                    else:
                        bnk_table.addNewRow(table_head, row)
                        inserted_transactions += 1
                else:
                    # print('**table_head', table_head)
                    # print('**row', row)
                    # print(len(table_head), len(row))
                    bnk_table.addNewRow(table_head, row)
                    inserted_transactions += 1
            # print('total_transactions', total_transactions)
            # print('inserted_transactions', inserted_transactions)
            # print('not_inserted_transactions', not_inserted_transactions)
            # #print(start, start)
            # self.add_row_to_imported_csv(str(inpFile), currentConto, start, end, total_transactions, inserted_transactions)
            self.imported_csv.changeCellContent('start', start, 'id', csv_id_row_no)
            self.imported_csv.changeCellContent('end', end, 'id', csv_id_row_no)
            self.imported_csv.changeCellContent('total_rows', total_transactions, 'id', csv_id_row_no)
            self.imported_csv.changeCellContent('imported_rows', inserted_transactions, 'id', csv_id_row_no)

    def remove_intercontotrans(self, payments4Interval):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        new_payments4Interval = []
        category_col_indx = self.plan_vs_real.columnsNames.index('category')
        for row in payments4Interval:
            # #print('ßß', row[category_col_indx])
            if row[category_col_indx] == 'intercontotrans':
                continue
            else:
                new_payments4Interval.append(row)
        return new_payments4Interval

    def get_unplanned_chelt_from_bank_table(self, currentConto, selectedStartDate, selectedEndDate):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        chelt_not_in_plan_vs_real = []
        matches = [('Buchungstag', '>=', selectedStartDate),
                   ('Buchungstag', '<=', selectedEndDate),
                   ('id_plan_vs_real', 'IS', None)]
        table_list = []
        if currentConto != 'all':
            tup = ('myconto', '=', currentConto)
            matches.append(tup)
            banca = self.myAccountsTable.returnCellsWhere('banca', ('name', currentConto))[0]
            sql_table_name = bank_sql_table[banca]
            table_list.append(sql_table_name)
        else:
            table_list = list(plan_vs_real_tabHeadDict.keys())

        for sql_table_name in table_list:
            # #print('****sql_table_name', sql_table_name)
            if sql_table_name == 'sskm':
                table = self.sskm
            elif sql_table_name == 'n26':
                table = self.n26
            elif sql_table_name == 'deubnk':
                table = self.deubnk
            table_head = table.columnsNames
            # print('ÄHHHHHHmatches', matches)
            not_found_in_planned = table.returnRowsQuery(matches)
            tabHeadConversion = plan_vs_real_tabHeadDict[sql_table_name]
            for nf in not_found_in_planned:
                # print('***nf', nf)
                new_row = []
                for col in self.plan_vs_real.columnsNames:
                    if col in table_head:
                        new_row.append(nf[table_head.index(col)])
                    elif col in list(tabHeadConversion.keys()):
                        if sql_table_name == 'deubnk' and col == 'Betrag':
                            betrag_val = float(nf[table_head.index(tabHeadConversion[col])])
                            if betrag_val == 0:
                                # print('****nf[table_head.index(tabHeadConversion[col])]', nf[table_head.index(tabHeadConversion[col])])
                                # print('****nf[table_head.index(tabHeadConversion[col])]', nf[table_head.index('Credit')])
                                new_row.append(nf[table_head.index('Credit')])
                            else:
                                new_row.append(nf[table_head.index(tabHeadConversion[col])])
                        else:
                            new_row.append(nf[table_head.index(tabHeadConversion[col])])
                    else:
                        new_row.append(None)
                chelt_not_in_plan_vs_real.append(tuple(new_row))
        return chelt_not_in_plan_vs_real

    def prepareTableReal_new(self, currentConto, selectedStartDate, selectedEndDate, hideIntercontotrans):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print(sys._getframe().f_code.co_name)
        matches = [('Buchungstag', '>=', selectedStartDate),
                   ('Buchungstag', '<=', selectedEndDate)]
        if hideIntercontotrans:
            tup = ('category', '!=', 'intercontotrans')
            matches.append(tup)
        if currentConto != 'all':
            tup = ('myconto', '=', currentConto)
            matches.append(tup)
        payments4Interval = self.plan_vs_real.returnRowsQuery(matches)
        chelt_not_in_plan_vs_real = self.get_unplanned_chelt_from_bank_table(currentConto, selectedStartDate,
                                                                             selectedEndDate)
        for row in chelt_not_in_plan_vs_real:
            payments4Interval.append(row)

        payments, income = self.split_expenses_income(payments4Interval)
        self.realExpenses = np.atleast_2d(payments)
        self.realIncome = np.atleast_2d(income)

    def split_expenses_income(self, table):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print(sys._getframe().f_code.co_name)
        indxValue = self.plan_vs_real.columnsNames.index('Betrag')
        payments = []
        income = []
        for row in table:
            if row[indxValue] > 0:
                income.append(row)
            if row[indxValue] <= 0:
                payments.append(row)
        payments = np.atleast_2d(payments)
        income = np.atleast_2d(income)

        return payments, income

    def get_identification_from_chelt_plan_table(self, table):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        identification_arr = []
        active_table = table
        for row in active_table.returnAllRecordsFromTable():
            id = row[active_table.columnsNames.index('id')]
            identif = row[active_table.columnsNames.index('identification')]
            if identif:
                identif = identif.replace("'", '"')
                conditions = json.loads(identif)
                tup = (id, conditions, row)
                identification_arr.append(tup)
                # #print(tup)
        table_head_chelt_plan = active_table.columnsNames
        return identification_arr, table_head_chelt_plan

    # def get_index_plan_real_new(self, table_head, row, bank_table):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     identif = row[table_head.index('identification')]
    #     identif = identif.replace("'", '"')
    #     # print('#####identif', identif)
    #     conditions = json.loads(identif)
    #     # print(conditions)
    #     matches = []
    #     for col, search_value in conditions.items():
    #         # #print(col, search_value)
    #         if col == 'Verwendungszweck' or col == 'Beguenstigter' or col == 'PaymentReference':
    #             sign = 'LIKE'
    #         else:
    #             sign = '='
    #         tup = (col, sign, search_value)
    #         matches.append(tup)
    #     if 'valid_from' in table_head:
    #         tup = ('Buchungstag', '>', row[table_head.index('valid_from')])
    #         matches.append(tup)
    #     if 'valid_to' in table_head and row[table_head.index('valid_to')]:
    #         tup = ('Buchungstag', '<', row[table_head.index('valid_to')])
    #         matches.append(tup)
    #
    #     if bank_table == 'sskm':
    #         bank_table = self.sskm
    #     elif bank_table == 'n26':
    #         bank_table = self.n26
    #     elif bank_table == 'deubnk':
    #         bank_table = self.deubnk
    #
    #     found_rows = bank_table.returnRowsQuery(matches)
    #     return found_rows

    # def get_index_knowntrans_real_new(self, table_head, row, bank_table):
    #     print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,sys._getframe().f_back.f_code.co_name))
    #     identif = row[table_head.index('identification')]
    #     identif = identif.replace("'", '"')
    #     conditions = json.loads(identif)
    #     # #print(conditions)
    #     matches = [('id_plan_vs_real', 'IS', None)]
    #     for col, search_value in conditions.items():
    #         # #print(col, search_value)
    #         if col == 'Verwendungszweck' or col == 'Beguenstigter' or col == 'PaymentReference':
    #             sign = 'LIKE'
    #         else:
    #             sign = '='
    #         tup = (col, sign, search_value)
    #         matches.append(tup)
    #     if 'valid_from' in table_head:
    #         tup = ('Buchungstag', '>', row[table_head.index('valid_from')])
    #         matches.append(tup)
    #     if 'valid_to' in table_head and row[table_head.index('valid_to')]:
    #         tup = ('Buchungstag', '<', row[table_head.index('valid_to')])
    #         matches.append(tup)
    #
    #     if bank_table == 'sskm':
    #         bank_table = self.sskm
    #     elif bank_table == 'n26':
    #         bank_table = self.n26
    #     elif bank_table == 'deubnk':
    #         bank_table = self.deubnk
    #     try:
    #         found_rows = bank_table.returnRowsQuery(matches)
    #     except:
    #         print('def get_index_knowntrans_real_new', traceback.format_exc())
    #         return None
    #     return found_rows

    def find_identification_in_bank_tables(self, identif, bank_table, valid_from=None, valid_to=None):
        print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
                                                                  sys._getframe().f_back.f_code.co_name))
        identif = identif.replace("'", '"')
        conditions = json.loads(identif)
        # #print(conditions)
        matches = [('id_plan_vs_real', 'IS', None)]
        for col, search_value in conditions.items():
            # #print(col, search_value)
            if col == 'Verwendungszweck' or col == 'Beguenstigter' or col == 'PaymentReference':
                sign = 'LIKE'
            else:
                sign = '='
            tup = (col, sign, search_value)
            matches.append(tup)
        if valid_from:
            tup = ('Buchungstag', '>', valid_from)
            matches.append(tup)
        if valid_to:
            tup = ('Buchungstag', '<', valid_to)
            matches.append(tup)

        if bank_table == 'sskm':
            bank_table = self.sskm
        elif bank_table == 'n26':
            bank_table = self.n26
        elif bank_table == 'deubnk':
            bank_table = self.deubnk
        try:
            found_rows = bank_table.returnRowsQuery(matches)
        # except mysql.connector.errors.ProgrammingError:
        #     print('ÄÄÄÄÄÄÄÄ')
        except Exception as err:
            # print(traceback.format_exc())
            # print('##########err', err.args)
            print('##########err', err.msg)
            return None
        # except:
        #     print('def find_identification_in_bank_tables', traceback.format_exc())
        #     return None
        return found_rows

    def write_cols_in_real_table_new(self, table_head, row, found_rows, planorknown, bank_table):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        plan_vs_real_table = self.plan_vs_real
        if bank_table == 'sskm':
            sql_bank_table = self.sskm
            col_id_bank = 'id_bank_sskm'
        elif bank_table == 'n26':
            sql_bank_table = self.n26
            col_id_bank = 'id_bank_n26'
        elif bank_table == 'deubnk':
            sql_bank_table = self.deubnk
            col_id_bank = 'id_bank_deubnk'

        id_ch_pl = row[table_head.index('id')]
        category = row[table_head.index('category')]
        # if 'myconto' in table_head:
        #     myconto = row[table_head.index('myconto')]
        name = row[table_head.index('name')]
        plannedvalue = row[table_head.index('value')]
        pl_vs_re_thDict = plan_vs_real_tabHeadDict[bank_table]
        for found_row in found_rows:
            cols = ['id_users', 'id_ch_pl', 'category', 'name', 'plannedvalue', 'planorknown', 'bank_table']
            vals = [1, id_ch_pl, category, name, plannedvalue, planorknown, bank_table]
            id_bank_table = found_row[0]
            cols.append(col_id_bank)
            vals.append(id_bank_table)
            for col_pl_vs_re, col_bnk_table in pl_vs_re_thDict.items():
                val = found_row[sql_bank_table.columnsNames.index(col_bnk_table)]
                if bank_table == 'deubnk' and val == float(0):
                    val = found_row[sql_bank_table.columnsNames.index('Credit')]
                # #print('col_pl_vs_re, col_bnk_table, val', col_pl_vs_re, col_bnk_table, val)
                cols.append(col_pl_vs_re)
                vals.append(val)
            # continue
            matches = [('bank_table', bank_table),
                       (col_id_bank, id_bank_table),
                       ('id_ch_pl', id_ch_pl)]
            found_ids = plan_vs_real_table.returnCellsWhere('id', matches)
            if found_ids:
                # #print('cols', cols)
                # #print('vals', vals)
                print('already in table, skipping...', found_row)
            else:
                # #print('cols', len(cols), cols)
                # #print('vals', len(vals), vals)
                lastrowid = plan_vs_real_table.addNewRow(cols, vals)
                sql_bank_table.changeCellContent('id_plan_vs_real', lastrowid, 'id', id_bank_table)
        # print('FINISH')

    # def find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table(self):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     tables_2_check = [self.chelt_plan, self.knowntrans]
    #     for tab in tables_2_check:
    #         identification_arr, table_head = self.get_identification_from_chelt_plan_table(tab)
    #         for id, conditions, row in identification_arr:
    #             print('id, conditions, row', id, conditions, row)
    #             for sql_bank_table_name in list(bank_sql_table.values()):
    #                 # #print(sql_bank_table_name)
    #                 found_rows = self.get_index_knowntrans_real_new(table_head, row, sql_bank_table_name)
    #                 if not found_rows:
    #                     print('no rows found in bank table')
    #                     continue
    #                 # else:
    #                 # for ii in found_rows:
    #                 #     #print('&', ii)
    #                 self.write_cols_in_real_table_new(table_head, row, found_rows, sql_bank_table_name)

    def find_all_rows_with_identifications_and_write_to_plan_vs_real_table(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        tables_2_check = {'chelt_plan': self.chelt_plan, 'knowntrans': self.knowntrans}
        for tab in tables_2_check:
            identification_arr, table_head = self.get_identification_from_chelt_plan_table(tables_2_check[tab])
            for id, conditions, row in identification_arr:
                # print('id, conditions, row', id, conditions, row)
                # print('id, tab', id, tab)
                self.check_1_row_from_chelt_plan_knowntrans(source_table=tab, row_id=id, write_in_real_table=True)

    # def check_1_row_from_chelt_plan(self, row_id, write_in_real_table=False):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     chelt_plan_table = self.chelt_plan
    #     table_head_chelt_plan = chelt_plan_table.columnsNames
    #     match = ('id', row_id)
    #     row = chelt_plan_table.returnRowsWhere(match)[0]
    #     currentConto = row[table_head_chelt_plan.index('myconto')]
    #     matches = ('name', currentConto)
    #     banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]
    #     sql_bank_table_name = bank_sql_table[banca]
    #     found_rows = self.get_index_knowntrans_real_new(table_head_chelt_plan, row, sql_bank_table_name)
    #     for rr in found_rows:
    #         print(rr)
    #     if write_in_real_table:
    #         self.write_cols_in_real_table_new(table_head_chelt_plan, row, found_rows, sql_bank_table_name)

    # def check_1_row_from_knowntrans(self, row_id, currentConto, write_in_real_table=False):
    #     print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
    #     table_head_knowntrans = self.knowntrans.columnsNames
    #     match = ('id', row_id)
    #     row = self.knowntrans.returnRowsWhere(match)[0]
    #     # currentConto = row[table_head_chelt_plan.index('myconto')]
    #     matches = ('name', currentConto)
    #     banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]
    #     sql_bank_table_name = bank_sql_table[banca]
    #     found_rows = self.get_index_knowntrans_real_new(table_head_knowntrans, row, sql_bank_table_name)
    #     for rr in found_rows:
    #         print('found_row', rr)
    #     if write_in_real_table:
    #         self.write_cols_in_real_table_new(table_head_knowntrans, row, found_rows, sql_bank_table_name)

    def check_1_row_from_chelt_plan_knowntrans(self, source_table, row_id, write_in_real_table=False):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        if source_table == 'chelt_plan':
            table = self.chelt_plan
        elif source_table == 'knowntrans':
            table = self.knowntrans

        table_head_knowntrans = table.columnsNames
        match = ('id', row_id)
        row = table.returnRowsWhere(match)[0]
        # print(row)
        identif = row[table_head_knowntrans.index('identification')]
        valid_from = None
        valid_to = None
        if 'valid_from' in table_head_knowntrans:
            valid_from = row[table_head_knowntrans.index('valid_from')]
        if 'valid_to' in table_head_knowntrans:
            valid_to = row[table_head_knowntrans.index('valid_to')]
        # print('identif, valid_from, valid_to', identif, valid_from, valid_to, type(valid_to))
        for sql_bank_table_name in bank_sql_table.values():
            found_rows = self.find_identification_in_bank_tables(identif, bank_table=sql_bank_table_name,
                                                                 valid_from=valid_from, valid_to=valid_to)
            if found_rows:
                # for rr in found_rows:
                #     print('found_row', rr)
                if write_in_real_table:
                    self.write_cols_in_real_table_new(table_head_knowntrans, row, found_rows, source_table,
                                                      sql_bank_table_name)

    def get_rows_from_chelt_plan_that_misses_in_banks(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        not_found = []
        identification_arr, table_head_chelt_plan = self.get_identification_from_chelt_plan_table('chelt_plan')
        for id, conditions, row in identification_arr:
            currentConto = row[table_head_chelt_plan.index('myconto')]
            matches = ('name', currentConto)
            banca = self.myAccountsTable.returnCellsWhere('banca', matches)[0]
            sql_bank_table_name = bank_sql_table[banca]
            # #print(currentConto, banca, sql_bank_table_name)
            found_rows = self.get_index_knowntrans_real_new(table_head_chelt_plan, row, sql_bank_table_name)
            if not found_rows:
                # print(row)
                not_found.append(row)
        # return not_found

    def add_conto(self, user_id, name, banca):
        cols = ('id_users', 'name', 'banca')
        vals = (user_id, name, banca)
        self.myAccountsTable.addNewRow(cols, vals)

    def vals_for_grafik(self, table_dates, selectedStartDate, selectedEndDate):
        first_date = None
        last_date = None
        for i, (bank, interval) in enumerate(table_dates.items()):
            print(i, bank, interval)
            start_date, end_date = interval
            if not first_date:
                first_date = start_date
            else:
                first_date = min(first_date, start_date)

            if not last_date:
                last_date = end_date
            else:
                last_date = max(last_date, end_date)

        first_date = min(selectedStartDate, first_date)
        last_date = max(selectedEndDate, last_date)

        # print('first_date', first_date)
        # print('last_date', last_date)
        graf_range = (last_date - first_date).days
        # print(graf_range)
        graf_adapted_dict = {}
        for i, (bank, interval) in enumerate(table_dates.items()):
            start_date, end_date = interval
            xpos_start = (start_date - first_date).days
            xpos_end = (end_date - first_date).days
            graf_adapted_dict[bank] = [xpos_start, xpos_end]
            # print(bank, xpos_start, xpos_end)
        graf_adapted_dict['graf_range'] = [0, graf_range]
        return graf_adapted_dict

    def returnNonUniqRows(self, bank, colsNames):
        if bank == 'Stadtsparkasse München':
            sql_table = self.sskm
        elif bank == 'DeutscheBank':
            sql_table = self.deubnk
        elif bank == 'N26':
            sql_table = self.n26

        array = sql_table.returnAllRecordsFromTable()
        table = np.atleast_2d(array)
        table_head = sql_table.columnsNames
        colsValues = []
        for col in colsNames:
            colVal = table[:, table_head.index(col)]
            colsValues.append(colVal)
        newArr = np.stack(colsValues, axis=1)

        # for i, row in enumerate(newArr):
        #     print('aaa', i, row)
        # print('newArr.shape', newArr.shape)
        arrUnique, uniq_idx, counts = np.unique(newArr.astype(str), axis=0, return_index=True, return_counts=True)
        # print('uniq_idx', uniq_idx, uniq_idx.shape)
        # print('arrUnique.shape', arrUnique.shape)
        a_idx = np.arange(newArr.shape[0])
        # print('a_idx', a_idx, a_idx.shape)
        # nonUniqIndx = a_idx[np.in1d(a_idx, uniq_idx[counts == 1], invert=True)]
        nonUniqIndx = np.setdiff1d(a_idx, uniq_idx)
        # print('nonUniqIndx', nonUniqIndx, nonUniqIndx.shape)
        nonUniqArray = table[nonUniqIndx]
        # print('nonUniqArray.shape', nonUniqArray.shape)
        return nonUniqArray

    def returnRowsFromTable_plan_vs_real_where_same_bank_table_and_id_bank_table(self):
        # if bank == 'Stadtsparkasse München':
        #     sql_table = self.sskm
        # elif bank == 'DeutscheBank':
        #     sql_table = self.deubnk
        # elif bank == 'N26':
        #     sql_table = self.n26
        colsNames = ['bank_table', 'id_bank_deubnk', 'id_bank_n26', 'id_bank_sskm']
        array = self.plan_vs_real.returnAllRecordsFromTable()
        table = np.atleast_2d(array)
        table_head = self.plan_vs_real.columnsNames
        colsValues = []
        for col in colsNames:
            colVal = table[:, table_head.index(col)]
            colsValues.append(colVal)
        newArr = np.stack(colsValues, axis=1)

        # for i, row in enumerate(newArr):
        #     print('aaa', i, row)
        # print('newArr.shape', newArr.shape)
        arrUnique, uniq_idx, counts = np.unique(newArr.astype(str), axis=0, return_index=True, return_counts=True)
        # print('uniq_idx', uniq_idx, uniq_idx.shape)
        # print('arrUnique.shape', arrUnique.shape)
        a_idx = np.arange(newArr.shape[0])
        # print('a_idx', a_idx, a_idx.shape)
        # nonUniqIndx = a_idx[np.in1d(a_idx, uniq_idx[counts == 1], invert=True)]
        nonUniqIndx = np.setdiff1d(a_idx, uniq_idx)
        # print('nonUniqIndx', nonUniqIndx, nonUniqIndx.shape)
        nonUniqArray = table[nonUniqIndx]
        # print('nonUniqArray.shape', nonUniqArray.shape)
        return nonUniqArray

    # def export_real_expenses_csvs(self):
    #
    #     tim = datetime.strftime(datetime.now(), '%Y_%m_%d__%H_%M_%S')
    #     output_dir = os.path.join(os.path.dirname(__file__), 'static', 'backup_profile',
    #                               '{:09d}'.format(self.id_users), 'real_expenses',
    #                               '{}_{:09d}'.format(tim, self.id_users))
    #     if not os.path.exists(output_dir):
    #         os.makedirs(output_dir)
    #
    #     match = ('id_users', self.id_users)
    #     rows = self.imported_csv.returnRowsWhere(match)
    #     for rr in rows:
    #         # print('rr**', rr)
    #         id_ = rr[0]
    #         file_name = rr[-1]
    #         output_file = os.path.join(output_dir, file_name)
    #         # print(output_file)
    #         file_content = self.imported_csv.returnCellsWhere('file', ('id', id_))[0]
    #         self.imported_csv.write_file(file_content, output_file)
    #     # #####
    #     output_zip = os.path.join(os.path.dirname(output_dir), '{}.zip'.format(output_dir))
    #     zip_file = self.zip_profile_files(output_dir, output_zip)
    #     if os.path.exists(zip_file):
    #         shutil.rmtree(output_dir)
    #     print('finished backup', output_zip)
    #     return zip_file

    def unzip_profile_files(self, src_file, output_dir):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        with zipfile.ZipFile(src_file, 'r') as zip_ref:
            zip_ref.extractall(output_dir)
        return output_dir

    def import_profile_bank_all_csvs(self, src_dir):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        # output_dir, file = os.path.split(zip_file)
        # src_dir = self.unzip_profile_files(zip_file, output_dir)
        # src_dir = os.path.join(src_dir, file[:-4])
        # if not os.path.exists(src_dir):
        #     raise RuntimeError('Missing Folder {}'.format(src_dir))
        src_dir = pathlib.Path(src_dir)
        imported_csvs = []
        not_imported_csvs = []
        for p in src_dir.rglob("*.csv".format()):
            print('****LLLLLp', p)
            currentConto = p.parent.name
            banca = p.parent.parent.name
            # print('ÖÖÖÖÖÖcurrentConto', currentConto)
            # print('ÄÄÄÄÄÄÄbanca', banca)
            # continue
            try:
                self.import_CSV_new(currentConto, p, banca=banca)
                imported_csvs.append(p)
            except:
                print(traceback.format_exc())
                not_imported_csvs.append(p)
        for fl in not_imported_csvs:
            print('not_imported_csv', fl)
        print('===================Finished to import all csvs')

    def import_real_expenses_csvs(self, zip_file, import_csvs=True):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))
        output_dir, file = os.path.split(zip_file)
        src_dir = self.unzip_profile_files(zip_file, output_dir)
        src_dir = os.path.join(src_dir, file[:-4])
        if not os.path.exists(src_dir):
            raise RuntimeError('Missing Folder {}'.format(src_dir))

        sql_files = [x for x in os.listdir(src_dir) if x.endswith('.sql')]
        sql_file = os.path.join(src_dir, sql_files[0])

        self.dataBase.run_sql_file(sql_file)
        if import_csvs:
            self.import_profile_bank_all_csvs(src_dir)

        if os.path.exists(src_dir):
            shutil.rmtree(src_dir)
        return zip_file

    # def write_real_expenses_yearly_all_old(self):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     # if not year:
    #     #     year = datetime.now().year
    #     # self.find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table()
    #     # self.find_knowntrans_in_banks_tables_and_write_to_plan_vs_real_table()
    #     all_years = []
    #     for conto, dates in self.imported_csv_dates.items():
    #         from_date, bis_date = dates
    #         all_years.append(from_date.year)
    #         all_years.append(bis_date.year)
    #     all_years = list(set(all_years))
    #     print('all_years******', all_years)
    #     start_year = min(all_years)
    #     end_year = max(all_years)
    #
    #     for year in range(start_year, end_year + 1):
    #         print(year)
    #         months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
    #         cols = ['id_users', 'db_update', 'expenses', 'myconto', 'January', 'February', 'March', 'April', 'May',
    #                 'June',
    #                 'July', 'August', 'September', 'October', 'November', 'December']
    #         self.prepareTableReal_new('all', datetime(year, 1, 1).date(), datetime(year, 12, 31), hideIntercontotrans=True)
    #         if self.realExpenses.shape == (1, 0):
    #             # raise RuntimeError('No expenses found for year {}'.format(year))
    #             print('No expenses found for year {}'.format(year))
    #             continue
    #         all_banks = list(self.expenses_per_conto.keys())
    #         rows_no = len(all_banks)
    #         newTableData = np.empty([rows_no, len(cols)], dtype=object)
    #         newTableData[:, 0] = self.id_users
    #         newTableData[:, 1] = year
    #         newTableData[:, 2] = 'real_expenses'
    #         indx_col_myconto = cols.index('myconto')
    #         # indx_col_expenses = cols.index('expenses')
    #         for month in months:
    #             print(month)
    #             col = cols.index(month)
    #             selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
    #             self.prepareTableReal_new('all', selectedStartDate, selectedEndDate, hideIntercontotrans=True)
    #             row_no = 0
    #             if self.expenses_per_conto:
    #                 for currentConto in all_banks:
    #                     if currentConto in self.expenses_per_conto.keys():
    #                         value = self.expenses_per_conto[currentConto]
    #                         value = float(value[0])
    #                     else:
    #                         value = None
    #                     newTableData[row_no, indx_col_myconto] = currentConto
    #                     newTableData[row_no, col] = value
    #                     print('\tcurrentConto, value', currentConto, value)
    #                     row_no += 1
    #
    #         for rw in newTableData:
    #             # print('####rw', rw)
    #             # continue2
    #             myconto, chelt_type = rw[3], rw[2]
    #             matches = [('id_users', '=', self.id_users),
    #                        ('myconto', '=', myconto),
    #                        ('expenses', '=', chelt_type),
    #                        ('db_update', '=', year),
    #                        ]
    #             rows = self.yearly_all.returnRowsQuery(matches)
    #             if rows:
    #                 print('already existing:', rows)
    #                 if len(rows) > 1:
    #                     raise RuntimeError('We have a problem')
    #                 else:
    #                     existing_row = rows[0]
    #                     rid = existing_row[0]
    #                     for cc in range(4, 16):
    #                         # print('cols[cc], row[cc]', cols[cc], rw[cc])
    #                         self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
    #             else:
    #                 self.yearly_all.addNewRow(cols, tuple(rw))
    #     print('########## finished to write_real_expenses_yearly_all')
    #     return newTableData

    # def write_real_income_yearly_all_old(self):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     # if not year:
    #     #     year = datetime.now().year
    #     # self.find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table()
    #     # self.find_knowntrans_in_banks_tables_and_write_to_plan_vs_real_table()
    #     all_years = []
    #     for conto, dates in self.imported_csv_dates.items():
    #         from_date, bis_date = dates
    #         all_years.append(from_date.year)
    #         all_years.append(bis_date.year)
    #     all_years = list(set(all_years))
    #     # all_years.sort()
    #     start_year = min(all_years)
    #     end_year = max(all_years)
    #
    #     for year in range(start_year, end_year + 1):
    #         print(year)
    #         months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
    #         cols = ['id_users', 'db_update', 'expenses', 'myconto', 'January', 'February', 'March', 'April', 'May',
    #                 'June',
    #                 'July', 'August', 'September', 'October', 'November', 'December']
    #         self.prepareTableReal_new('all', datetime(year, 1, 1).date(), datetime(year, 12, 31),
    #                                   hideIntercontotrans=True)
    #         if self.realIncome.shape == (1, 0):
    #             # raise RuntimeError('No expenses found for year {}'.format(year))
    #             print('No income found for year {}'.format(year))
    #             continue
    #
    #         all_banks = list(self.expenses_per_conto.keys())
    #         rows_no = len(all_banks)
    #         newTableData = np.empty([rows_no, len(cols)], dtype=object)
    #         newTableData[:, 0] = self.id_users
    #         newTableData[:, 1] = year
    #         newTableData[:, 2] = 'real_income'
    #         indx_col_myconto = cols.index('myconto')
    #         # indx_col_expenses = cols.index('expenses')
    #         for month in months:
    #             print(month)
    #             col = cols.index(month)
    #             # all_contos_monthly_tot_val_of_expenses = 0
    #             selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
    #             self.prepareTableReal_new('all', selectedStartDate, selectedEndDate, hideIntercontotrans=True)
    #             row_no = 0
    #             if self.income_per_conto:
    #                 # for currentConto, value in self.expenses_per_conto.items():
    #                 #     # print('\t\t', 'tot_val_of_expeYnses', self.tot_val_of_expenses)
    #                 #     newTableData[row_no, indx_col_myconto] = currentConto
    #                 #     value = float(value[0])
    #                 #     newTableData[row_no, col] = value
    #                 #     print('\tcurrentConto, value', currentConto, value)
    #                 #     row_no += 1
    #                 for currentConto in all_banks:
    #                     if currentConto in self.income_per_conto.keys():
    #                         value = self.income_per_conto[currentConto]
    #                         value = float(value[0])
    #                     else:
    #                         value = None
    #                         # print('\t\t', 'tot_val_of_expeYnses', self.tot_val_of_expenses)
    #                     newTableData[row_no, indx_col_myconto] = currentConto
    #                     newTableData[row_no, col] = value
    #                     print('\tcurrentConto, value', currentConto, value)
    #                     row_no += 1
    #
    #         for rw in newTableData:
    #             # print('####rw', rw)
    #             # continue2
    #             myconto, chelt_type = rw[3], rw[2]
    #             matches = [('id_users', '=', self.id_users),
    #                        ('myconto', '=', myconto),
    #                        ('expenses', '=', chelt_type),
    #                        ('db_update', '=', year),
    #                        ]
    #             rows = self.yearly_all.returnRowsQuery(matches)
    #             if rows:
    #                 print('already existing:', rows)
    #                 if len(rows) > 1:
    #                     raise RuntimeError('We have a problem')
    #                 else:
    #                     existing_row = rows[0]
    #                     rid = existing_row[0]
    #                     for cc in range(4, 16):
    #                         # print('cols[cc], row[cc]', cols[cc], rw[cc])
    #                         self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
    #             else:
    #                 self.yearly_all.addNewRow(cols, tuple(rw))
    #     print('########## finished to write_real_income_yearly_all')
    #     return newTableData

    def write_real_expenses_yearly_all(self, write_to_sql=True):
        print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
                                                                  sys._getframe().f_back.f_code.co_name))
        # if not year:
        #     year = datetime.now().year
        # self.find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table()
        # self.find_knowntrans_in_banks_tables_and_write_to_plan_vs_real_table()
        all_years = []
        for conto, dates in self.imported_csv_dates.items():
            from_date, bis_date = dates
            all_years.append(from_date.year)
            all_years.append(bis_date.year)
        all_years = list(set(all_years))
        print('all_years******', all_years)
        start_year = min(all_years)
        end_year = max(all_years)

        for year in range(start_year, end_year + 1):
            print(year)
            months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
            cols = (
                'id_users', 'db_update', 'expenses', 'myconto', 'category', 'January', 'February', 'March', 'April',
                'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
            # newTableData = [cols]
            index_january = cols.index('January')
            self.prepareTableReal_new('all', datetime(year, 1, 1).date(), datetime(year, 12, 31),
                                      hideIntercontotrans=False)
            if self.realExpenses.shape == (1, 0):
                # raise RuntimeError('No expenses found for year {}'.format(year))
                print('No expenses found for year {}'.format(year))
                continue
            all_banks = list(self.expenses_per_conto.keys())
            # rows_no = len(all_banks)
            # rows_no = 0
            tv, ttrno, dict_all_categories = self.expenses_per_conto_per_category['all']
            all_catgories_per_year = list(dict_all_categories.keys())
            # all_catgories_per_year = self.categories
            rows_no = len(all_banks) * len(all_catgories_per_year) + len(all_banks)
            print('ÖÖÖÖrows_no', rows_no)
            newTableData = np.empty([rows_no, len(cols)], dtype=object)
            newTableData[:, cols.index('id_users')] = self.id_users
            newTableData[:, cols.index('db_update')] = year
            newTableData[:, cols.index('expenses')] = 'real_expenses'
            indx_col_myconto = cols.index('myconto')
            indx_col_category = cols.index('category')
            for month in months:
                print(month)
                col = cols.index(month)
                # all_contos_monthly_tot_val_of_expenses = 0
                selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
                self.prepareTableReal_new('all', selectedStartDate, selectedEndDate, hideIntercontotrans=False)
                row_no = 0
                if self.expenses_per_conto_per_category:
                    for currentConto in all_banks:
                        if currentConto in self.expenses_per_conto_per_category.keys():
                            tot_val_per_conto_per_month, tot_trans_per_conto_per_month, dict_all_categories_per_month = \
                                self.expenses_per_conto_per_category[currentConto]
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = 'all'
                            newTableData[row_no, col] = tot_val_per_conto_per_month
                            row_no += 1
                            for cat in all_catgories_per_year:
                                if cat in dict_all_categories_per_month.keys():
                                    value, noofranspermont = dict_all_categories_per_month[cat]
                                    value = float(value)
                                    newTableData[row_no, indx_col_myconto] = currentConto
                                    newTableData[row_no, indx_col_category] = cat
                                    newTableData[row_no, col] = value
                                    row_no += 1
                                else:
                                    newTableData[row_no, indx_col_myconto] = currentConto
                                    newTableData[row_no, indx_col_category] = cat
                                    newTableData[row_no, col] = 0
                                    row_no += 1
                        else:
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = 'all'
                            newTableData[row_no, col] = 0
                            row_no += 1
                            for cat in all_catgories_per_year:
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = 0
                                # print('\tcurrentConto, value', currentConto, value)
                                row_no += 1

            print('****newTableData', )
            for iijj in newTableData:
                print(iijj)
            # sys.exit()
            if write_to_sql:
                for rw in newTableData:
                    # print('####rw', rw)
                    # continue2
                    myconto, chelt_type, category = rw[indx_col_myconto], rw[2], rw[indx_col_category]
                    matches = [('id_users', '=', self.id_users),
                               ('db_update', '=', year),
                               ('expenses', '=', chelt_type),
                               ('myconto', '=', myconto),
                               ('category', '=', category),
                               ]
                    rows = self.yearly_all.returnRowsQuery(matches)
                    if rows:
                        print('trying to write:', rw)
                        print('already existing:', rows)
                        if len(rows) > 1:
                            raise RuntimeError('We have a problem')
                        else:
                            existing_row = rows[0]
                            rid = existing_row[0]
                            for cc in range(index_january, len(cols)):
                                # print('cols[cc], row[cc]', cols[cc], rw[cc])
                                self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
                    else:
                        self.yearly_all.addNewRow(cols, tuple(rw))
        print('########## finished to write_real_expenses_yearly_all')
        return newTableData

    def write_real_income_yearly_all(self, write_to_sql=True):
        print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
                                                                  sys._getframe().f_back.f_code.co_name))
        # if not year:
        #     year = datetime.now().year
        # self.find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table()
        # self.find_knowntrans_in_banks_tables_and_write_to_plan_vs_real_table()
        all_years = []
        for conto, dates in self.imported_csv_dates.items():
            from_date, bis_date = dates
            all_years.append(from_date.year)
            all_years.append(bis_date.year)
        all_years = list(set(all_years))
        print('all_years******', all_years)
        start_year = min(all_years)
        end_year = max(all_years)

        for year in range(start_year, end_year + 1):
            print(year)
            months = [dt.date(2000, m, 1).strftime('%B') for m in range(1, 13)]
            cols = (
                'id_users', 'db_update', 'expenses', 'myconto', 'category', 'January', 'February', 'March', 'April',
                'May',
                'June', 'July', 'August', 'September', 'October', 'November', 'December')
            index_january = cols.index('January')
            # newTableData = [cols]
            self.prepareTableReal_new('all', datetime(year, 1, 1).date(), datetime(year, 12, 31),
                                      hideIntercontotrans=False)
            if self.realIncome.shape == (1, 0):
                # raise RuntimeError('No expenses found for year {}'.format(year))
                print('No expenses found for year {}'.format(year))
                continue
            all_banks = list(self.income_per_conto_per_category.keys())
            # rows_no = len(all_banks)
            # rows_no = 0
            tv, ttrno, dict_all_categories = self.income_per_conto_per_category['all']
            all_catgories_per_year = list(dict_all_categories.keys())
            rows_no = len(all_banks) * len(all_catgories_per_year) + len(all_banks)
            print('ÖÖÖÖrows_no', rows_no)
            newTableData = np.empty([rows_no, len(cols)], dtype=object)
            newTableData[:, cols.index('id_users')] = self.id_users
            newTableData[:, cols.index('db_update')] = year
            newTableData[:, cols.index('expenses')] = 'real_income'
            indx_col_myconto = cols.index('myconto')
            indx_col_category = cols.index('category')
            for month in months:
                print(month)
                col = cols.index(month)
                # all_contos_monthly_tot_val_of_expenses = 0
                selectedStartDate, selectedEndDate = (get_monthly_interval(month, year))
                self.prepareTableReal_new('all', selectedStartDate, selectedEndDate, hideIntercontotrans=False)
                row_no = 0
                if self.income_per_conto_per_category:
                    for currentConto in all_banks:
                        if currentConto in self.income_per_conto_per_category.keys():
                            tot_val_per_conto_per_month, tot_trans_per_conto_per_month, dict_all_categories_per_month = \
                                self.income_per_conto_per_category[currentConto]
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = 'all'
                            newTableData[row_no, col] = tot_val_per_conto_per_month
                            row_no += 1
                            for cat in all_catgories_per_year:
                                if cat in dict_all_categories_per_month.keys():
                                    value, noofranspermont = dict_all_categories_per_month[cat]
                                    value = float(value)
                                    newTableData[row_no, indx_col_myconto] = currentConto
                                    newTableData[row_no, indx_col_category] = cat
                                    newTableData[row_no, col] = value
                                    row_no += 1
                                else:
                                    newTableData[row_no, indx_col_myconto] = currentConto
                                    newTableData[row_no, indx_col_category] = cat
                                    newTableData[row_no, col] = 0
                                    row_no += 1
                        else:
                            newTableData[row_no, indx_col_myconto] = currentConto
                            newTableData[row_no, indx_col_category] = 'all'
                            newTableData[row_no, col] = 0
                            row_no += 1
                            for cat in all_catgories_per_year:
                                newTableData[row_no, indx_col_myconto] = currentConto
                                newTableData[row_no, indx_col_category] = cat
                                newTableData[row_no, col] = None
                                # print('\tcurrentConto, value', currentConto, value)
                                row_no += 1

            print('****newTableData', )
            for iijj in newTableData:
                print(iijj)
            # sys.exit()
            if write_to_sql:
                for rw in newTableData:
                    # print('####rw', rw)
                    # continue2
                    myconto, chelt_type, category = rw[indx_col_myconto], rw[2], rw[indx_col_category]
                    matches = [('id_users', '=', self.id_users),
                               ('db_update', '=', year),
                               ('expenses', '=', chelt_type),
                               ('myconto', '=', myconto),
                               ('category', '=', category),
                               ]
                    rows = self.yearly_all.returnRowsQuery(matches)
                    if rows:
                        print('trying to write:', rw)
                        print('already existing:', rows)
                        if len(rows) > 1:
                            raise RuntimeError('We have a problem')
                        else:
                            existing_row = rows[0]
                            rid = existing_row[0]
                            for cc in range(index_january, len(cols)):
                                # print('cols[cc], row[cc]', cols[cc], rw[cc])
                                self.yearly_all.changeCellContent(cols[cc], rw[cc], 'id', rid)
                    else:
                        self.yearly_all.addNewRow(cols, tuple(rw))
        print('########## finished to write_real_expenses_yearly_all')
        return newTableData

    def write_real_yearly_all(self, write_to_sql=True):
        print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
                                                                  sys._getframe().f_back.f_code.co_name))
        self.write_real_expenses_yearly_all(write_to_sql=write_to_sql)
        self.write_real_income_yearly_all(write_to_sql=write_to_sql)

    def reset_plan_vs_real(self, ):
        # UPDATE `sskm` SET `id_plan_vs_real` = NULL;
        # UPDATE `n26` SET `id_plan_vs_real` = NULL;
        # UPDATE `deubnk` SET `id_plan_vs_real` = NULL;
        # DELETE FROM `plan_vs_real`;
        self.n26.changeAllColumnValues(columnName='id_plan_vs_real', value='NULL')
        self.sskm.changeAllColumnValues(columnName='id_plan_vs_real', value='NULL')
        self.deubnk.changeAllColumnValues(columnName='id_plan_vs_real', value='NULL')
        self.plan_vs_real.deleteAllDataFromTable()
        return

    def category_values4pie(self):
        total_monthly_values = self.expenses_per_category['all']
        total_monthly_values = total_monthly_values[0]
        pielabels = []
        piesizes = []
        for myConto, yearly_list in self.expenses_per_category.items():
            if myConto == 'all':
                continue
            # print('myConto::planned_payments_dict, yearly_list, ', myConto, yearly_list, )
            value = yearly_list[0]
            txt = '{} = {:.2f}'.format(myConto, value)
            pielabels.append(txt)
            size = (value / total_monthly_values) * 100
            piesizes.append(size)
        return piesizes, pielabels, total_monthly_values

    def names_values4pie(self):
        total_monthly_values = self.expenses_per_name['all']
        total_monthly_values = total_monthly_values[0]
        pielabels = []
        piesizes = []

        for myConto, yearly_list in self.expenses_per_name.items():
            if myConto == 'all':
                continue
            # print('myConto::planned_payments_dict, yearly_list, ', myConto, yearly_list, )
            value = yearly_list[0]
            txt = '{} = {:.2f}'.format(myConto, value)
            pielabels.append(txt)
            size = (value / total_monthly_values) * 100
            piesizes.append(size)
        return piesizes, pielabels, total_monthly_values

    def delete_from_plan_vs_real_and_id_from_bank_table(self, ids_plan_vs_real):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        # print('****ids_plan_vs_real', ids_plan_vs_real, type(ids_plan_vs_real))
        if len(ids_plan_vs_real) == 1:
            match = ('id', int(ids_plan_vs_real[0]))
        else:
            match = ('id', tuple(ids_plan_vs_real))
        rows = self.plan_vs_real.returnRowsWhere(match)
        # print('ÖÖÖÖÖrows', rows)
        for rr in rows:
            # print('rr###', rr)
            sql_table_name = rr[self.plan_vs_real.columnsNames.index('bank_table')]
            if sql_table_name == 'sskm':
                table = self.sskm
                col_id_bank = 'id_bank_sskm'
            elif sql_table_name == 'n26':
                table = self.n26
                col_id_bank = 'id_bank_n26'
            elif sql_table_name == 'deubnk':
                table = self.deubnk
                col_id_bank = 'id_bank_deubnk'
            id_bank_table = rr[self.plan_vs_real.columnsNames.index(col_id_bank)]
            # print('sql_table_name, id_bank_table', sql_table_name, id_bank_table)
            table.changeCellContent('id_plan_vs_real', None, 'id', id_bank_table)

        for idd in ids_plan_vs_real:
            condition = ('id', idd)
            self.plan_vs_real.delete_multiple_rows(condition)
        print('done')
        return

    def download_csv_file(self, csv_id):
        file_name = self.imported_csv.returnCellsWhere('file_name', ('id', csv_id))[0]
        file_content = self.imported_csv.returnCellsWhere('file', ('id', csv_id))[0]
        # print('ääääääfile_name', file_name)
        # print('ääääääpathlib.Path(__file__)', pathlib.Path(__file__))
        # temp_folder_pth = pathlib.Path(__file__).parent

        temp_folder_pth = os.path.join(os.path.dirname(__file__), 'temp')
        if not os.path.exists(temp_folder_pth):
            os.makedirs(temp_folder_pth)
            print('created {}'.format(temp_folder_pth))
        expName = os.path.join(temp_folder_pth, file_name)
        self.imported_csv.write_file(file_content, expName)
        os.startfile(expName)

    def add_row_to_knowntrans(self, currentConto, id_bank_table_row, identif_cols_name_category):
        bank = self.get_bank(currentConto)
        if bank == 'Stadtsparkasse München':
            sql_table = self.sskm
        elif bank == 'DeutscheBank':
            sql_table = self.deubnk
        elif bank == 'N26':
            sql_table = self.n26
        identif = {}
        for col in identif_cols_name_category['identification']:
            matches = [('id', id_bank_table_row)]
            cells = sql_table.returnCellsWhere(col, matches)
            identif[col] = cells[0]
        cols = ('id_users', 'name', 'category', 'identification')
        vals = (self.id_users, identif_cols_name_category['name'], identif_cols_name_category['category'], str(identif))
        rowid = self.knowntrans.addNewRow(columns=cols, values=vals)
        print('LLLLLLLLLLLrowid', rowid)

    def add_row_to_chelt_plan(self, currentConto, id_bank_table_row, identif_cols_name_category):
        bank = self.get_bank(currentConto)
        if bank == 'Stadtsparkasse München':
            sql_table = self.sskm
            value_col = 'Betrag'
        elif bank == 'DeutscheBank':
            sql_table = self.deubnk
            value_col = 'Debit'
        elif bank == 'N26':
            sql_table = self.n26
            value_col = 'Amount'
        identif = {}
        for col in identif_cols_name_category['identification']:
            matches = [('id', id_bank_table_row)]
            cells = sql_table.returnCellsWhere(col, matches)
            identif[col] = cells[0]

        matches = [('id', id_bank_table_row)]
        cells_value = sql_table.returnCellsWhere(value_col, matches)
        value = cells_value[0]
        matches = [('id', id_bank_table_row)]
        cells_pay_day = sql_table.returnCellsWhere('Buchungstag', matches)
        pay_day = cells_pay_day[0]
        # print('ÖÖÖÖÖÖÖpay_day', pay_day, type(pay_day))
        cols = (
            'id_users', 'name', 'category', 'myconto', 'identification', 'freq', 'valid_from', 'valid_to', 'auto_ext',
            'value', 'pay_day')
        vals = (self.id_users,
                identif_cols_name_category['name'],
                identif_cols_name_category['category'],
                currentConto,
                str(identif),
                identif_cols_name_category['freq'],
                identif_cols_name_category['valid_from'],
                identif_cols_name_category['valid_to'],
                identif_cols_name_category['auto_ext'],
                value,
                pay_day.day
                )
        rowid = self.chelt_plan.addNewRow(columns=cols, values=vals)
        print('LLLLLLLLLLLrowid', rowid)


class CheltPlanVSReal:
    def __init__(self, chelt_db, chelt_plan, yearly_plan,
                 myAccountsTable, imported_csv, plan_vs_real, knowntrans, sskm, deubnk, n26, yearly_all,
                 currentConto, selectedStartDate, selectedEndDate, hideintercontotrans, id_users):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.currentConto = currentConto
        self.selectedStartDate = selectedStartDate
        self.selectedEndDate = selectedEndDate
        self.displayExpensesTableHead = ['category', 'name', 'value', 'myconto', 'payDay', 'freq', 'real_payment_date',
                                         'real_payment_value']
        self.displayPlanVsRealTableHead = ['myconto', 'category', 'name', 'plannedvalue', 'Buchungstag',
                                           'Betrag', 'PaymentReference',
                                           'PartnerName']  # , 'Buchungstext', 'Beguenstigter', 'Verwendungszweck']

        self.chelt_app = CheltuieliPlanificate(chelt_db=chelt_db,
                                               chelt_plan=chelt_plan,
                                               yearly_plan=yearly_plan,
                                               yearly_all=yearly_all,
                                               id_users=id_users)

        self.chelt_app.prepareTablePlan(currentConto, selectedStartDate, selectedEndDate, hideintercontotrans)
        # #print(50*'8')
        # #print(self.chelt_app.tableHead)
        # #print(50*'8')
        self.hideintercontotrans = hideintercontotrans
        self.planned_table_head = self.chelt_app.tableHead
        self.app_reale = CheltuieliReale(chelt_db=chelt_db,
                                         myAccountsTable=myAccountsTable,
                                         imported_csv=imported_csv,
                                         chelt_plan=chelt_plan,
                                         plan_vs_real=plan_vs_real,
                                         knowntrans=knowntrans,
                                         sskm=sskm,
                                         deubnk=deubnk,
                                         n26=n26,
                                         yearly_all=yearly_all,
                                         id_users=id_users)

        self.found_payments_from_planned = None
        self.not_found_payments_from_planned = None
        self.unplanned_real_expenses = None

    def find_planned_in_real_expenses_table(self, hideintercontotrans, puffer_days_to_plann=15, ):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        found_payments_from_planned_table_head = list(self.chelt_app.tableHead)
        found_payments_from_planned_table_head.append('real_payment_date')
        found_payments_from_planned_table_head.append('real_payment_value')
        found_payments_from_planned = [tuple(found_payments_from_planned_table_head)]
        not_found_payments_from_planned = [tuple(self.chelt_app.tableHead)]
        self.app_reale.prepareTableReal_new(self.currentConto,
                                            self.selectedStartDate - timedelta(
                                                days=puffer_days_to_plann),
                                            self.selectedEndDate + timedelta(
                                                days=puffer_days_to_plann),
                                            hideintercontotrans)
        # #print(20*'realExpenses')
        # #print(realExpenses)
        # #print(20*'realExpenses')
        real_table_head = self.app_reale.plan_vs_real.columnsNames
        sum_realised = 0
        # sum_values_planned = 0
        self.used_real_expenses_indexes = []
        multiple_row = []
        rows_more_than_one_time = 0

        if self.app_reale.realExpenses.shape == (1, 0):
            return None

        for row in self.chelt_app.expenses:
            # #print('**', row)
            not_found = True
            row_id = row[self.planned_table_head.index('id')]
            category = row[self.planned_table_head.index('category')]
            name = row[self.planned_table_head.index('name')]
            payDay = row[self.planned_table_head.index('payDay')]
            value_planned = row[self.planned_table_head.index('value')]
            # #print(category, name, payDay)
            from_date = payDay - timedelta(days=puffer_days_to_plann)
            up_to_date = payDay + timedelta(days=puffer_days_to_plann)
            index = np.where((category == self.app_reale.realExpenses[:, real_table_head.index('category')]) &
                             (name == self.app_reale.realExpenses[:, real_table_head.index('name')])
                             )
            # #print('::', index, type(index))
            if self.app_reale.realExpenses[index].shape[0] > 0:
                for ind in index[0]:
                    r = self.app_reale.realExpenses[ind]
                    real_payment_date = r[real_table_head.index('Buchungstag')]
                    real_payment_value = r[real_table_head.index('Betrag')]
                    if from_date < real_payment_date < up_to_date:
                        not_found = False
                        found = list(row)
                        found.append(real_payment_date)
                        found.append(real_payment_value)
                        found_payments_from_planned.append(tuple(found))
                        sum_realised += real_payment_value
                        self.used_real_expenses_indexes.append(int(ind))
                        if row_id in list(set(multiple_row)):
                            rows_more_than_one_time += 1
                        else:
                            multiple_row.append(row_id)
                        # #print('\t',found)
                    # #print()
            # #print(200*'#')
            if not_found:
                # #print(row)
                not_found_payments_from_planned.append(tuple(row))
        # #print(self.chelt_app.tableHead)
        # #print(type())
        # #print(100*'*')
        # for i in found_payments_from_planned:
        #     #print(i)
        # #print(self.app_reale.plan_vs_real.columnsNames)
        # #print(self.chelt_app.expenses.shape)
        self.found_payments_from_planned = np.atleast_2d(found_payments_from_planned)
        self.not_found_payments_from_planned = np.atleast_2d(not_found_payments_from_planned)
        # return found_payments_from_planned, not_found_payments_from_planned

    def find_unplanned_real_expenses(self, hideintercontotrans, puffer_days_to_plann=15):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.app_reale.prepareTableReal_new(self.currentConto,
                                            self.selectedStartDate - timedelta(
                                                days=puffer_days_to_plann),
                                            self.selectedEndDate + timedelta(
                                                days=puffer_days_to_plann),
                                            hideintercontotrans)
        unplanned_real_expenses = [self.app_reale.plan_vs_real.columnsNames]
        # if realExpenses:
        if isinstance(self.app_reale.realExpenses, np.ndarray) and self.app_reale.realExpenses.shape[0] > 0:
            for ii, exp_row in enumerate(self.app_reale.realExpenses):
                # #print(ii, type(ii), ii in used_real_expenses_indexes)
                if ii not in self.used_real_expenses_indexes:
                    # continue
                    buchungstag = exp_row[self.app_reale.plan_vs_real.columnsNames.index('Buchungstag')]
                    # #print('buchungstag', buchungstag, self.selectedStartDate, self.selectedEndDate)
                    if self.selectedStartDate <= buchungstag <= self.selectedEndDate:
                        # #print(type(exp_row), exp_row.shape)
                        # #print('ßßßß', ii, exp_row)
                        unplanned_real_expenses.append(list(exp_row))
        self.unplanned_real_expenses = np.atleast_2d(unplanned_real_expenses)

    def convert_to_display_table(self, tableHead, table, displayTableHead):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # #print('Module: {}, Class: {}, Def: {}'.format(__name__, __class__, sys._getframe().f_code.co_name))
        newTableData = np.empty([table.shape[0], len(displayTableHead)], dtype=object)
        for i, col in enumerate(displayTableHead):
            try:
                indxCol = tableHead.index(col)
            except:
                continue
            newTableData[:, i] = table[:, indxCol]
        newTableData = np.insert(newTableData, 0, displayTableHead, 0)
        return newTableData

    @property
    def found_payments_from_planned_display_table(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        tableHead, table = list(self.found_payments_from_planned[0]), self.found_payments_from_planned[1:]
        return self.convert_to_display_table(tableHead, table, self.displayExpensesTableHead)

    @property
    def not_found_payments_from_planned_display_table(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        tableHead, table = list(self.not_found_payments_from_planned[0]), self.not_found_payments_from_planned[1:]
        return self.convert_to_display_table(tableHead, table, self.displayExpensesTableHead)

    @property
    def unplanned_myconto_dict(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head = list(self.unplanned_real_expenses[0])
        all_my_contos = list(set(self.unplanned_real_expenses[1:, table_head.index('myconto')]))
        # #print(all_my_contos)
        unplanned_myconto = {}
        for cc in all_my_contos:
            unplanned_myconto[cc] = []
        for row in self.unplanned_real_expenses[1:]:
            # #print(row)
            unplanned_myconto[row[table_head.index('myconto')]].append(row)
        return unplanned_myconto

    @property
    def sum_planned(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        sum_planned = sum(self.chelt_app.expenses[:, self.planned_table_head.index('value')])
        return round(sum_planned, 2)

    @property
    def no_of_transactions_planned(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        return self.chelt_app.expenses.shape[0]

    @property
    def sum_realised(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        self.app_reale.prepareTableReal_new(self.currentConto,
                                            self.selectedStartDate,
                                            self.selectedEndDate,
                                            self.hideintercontotrans)
        sum_realised = sum(
            self.app_reale.realExpenses[:, self.app_reale.plan_vs_real.columnsNames.index('Betrag')])
        return round(sum_realised, 0)

    @property
    def sum_realised_from_planned_found(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table = list(self.found_payments_from_planned[0]), self.found_payments_from_planned[1:]
        sum_realised_from_planned_found = sum(table[:, table_head.index('real_payment_value')])
        return round(sum_realised_from_planned_found, 2)

    @property
    def realised_from_planned_found_in_interval(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table = list(self.found_payments_from_planned[0]), self.found_payments_from_planned[1:]
        arr = table[(table[:, table_head.index('real_payment_date')] <= self.selectedEndDate) &
                    (self.selectedStartDate <= table[:, table_head.index('real_payment_date')])]
        realised_from_planned_found_in_interval = np.insert(arr, 0, table_head, 0)
        return realised_from_planned_found_in_interval

    @property
    def sum_realised_from_planned_found_in_interval(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table = list(
            self.realised_from_planned_found_in_interval[0]), self.realised_from_planned_found_in_interval[1:]
        sum_realised_from_planned_found_in_interval = sum(table[:, table_head.index('real_payment_value')])
        return round(sum_realised_from_planned_found_in_interval, 2)

    @property
    def sum_realised_from_not_found_payments_from_planned(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table = list(self.not_found_payments_from_planned[0]), self.not_found_payments_from_planned[1:]
        sum_realised_from_not_found_payments_from_planned = sum(table[:, table_head.index('value')])
        return round(sum_realised_from_not_found_payments_from_planned, 2)

    @property
    def sum_of_unplanned_real_expenses(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # for i in self.unplanned_real_expenses:
        #     #print('vvv', i)
        table_head, table = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        sum_of_unplanned_real_expenses = sum(table[:, table_head.index('Betrag')])
        return round(sum_of_unplanned_real_expenses, 2)

    @property
    def sum_of_unplanned_real_expenses_without_n26(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # for i in self.unplanned_real_expenses:
        #     #print('vvv', i)
        table_head, table = list(self.unplanned_real_expenses_without_N26[0]), self.unplanned_real_expenses_without_N26[
                                                                               1:]
        sum_of_unplanned_real_expenses = sum(table[:, table_head.index('Betrag')])
        return round(sum_of_unplanned_real_expenses, 2)

    @property
    def unplanned_real_expenses_without_N26(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        arr = table_data[table_data[:, table_head.index('myconto')] != 'N26']
        arr = arr[arr[:, table_head.index('myconto')] != 'N26 Family Mircea']
        arr = np.insert(arr, 0, table_head, 0)
        return arr

    @property
    def unplanned_real_expenses_only_N26(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        indx = np.where(table_data[:, table_head.index('myconto')] == 'N26')
        n26 = table_data[indx]
        # #print(n26.shape)
        indx = np.where(table_data[:, table_head.index('myconto')] == 'N26 Family Mircea')
        n26_family = table_data[indx]
        # #print(n26_family.shape)
        arr = np.vstack((n26, n26_family))
        # #print(arr)
        # #print(arr.shape)
        arr = np.insert(arr, 0, table_head, 0)
        return arr

    @property
    def sum_of_unplanned_real_expenses_only_n26(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        # for i in self.unplanned_real_expenses:
        #     #print('vvv', i)
        table_head, table = list(self.unplanned_real_expenses_only_N26[0]), self.unplanned_real_expenses_only_N26[1:]
        sum_of_unplanned_real_expenses = sum(table[:, table_head.index('Betrag')])
        return round(sum_of_unplanned_real_expenses)

    @property
    def unplanned_real_expenses_no_category(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        indx = np.where(table_data[:, table_head.index('category')] == None)
        no_cat = table_data[indx]
        arr = np.insert(no_cat, 0, table_head, 0)
        return arr

    @property
    def sum_of_unplanned_real_expenses_no_category(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        indx = np.where(table_data[:, table_head.index('category')] == None)
        no_cat = table_data[indx]
        sum_of_no_cat = sum(no_cat[:, table_head.index('Betrag')])
        return round(sum_of_no_cat, 2)

    @property
    def unplanned_real_expenses_with_category(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        indx = np.where(table_data[:, table_head.index('category')] != None)
        no_cat = table_data[indx]
        arr = np.insert(no_cat, 0, table_head, 0)
        return arr

    @property
    def sum_of_unplanned_real_expenses_with_category(self):
        #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
        #                                                                  sys._getframe().f_back.f_code.co_name))

        table_head, table_data = list(self.unplanned_real_expenses[0]), self.unplanned_real_expenses[1:]
        indx = np.where(table_data[:, table_head.index('category')] != None)
        no_cat = table_data[indx]
        sum_of_no_cat = sum(no_cat[:, table_head.index('Betrag')])
        return round(sum_of_no_cat, 2)


class CheltYearlyOnline:
    def __init__(self, chelt_db, yearly_all, id_users):
        # self.displayRealTableHead = ['myconto', 'category', 'name', 'plannedvalue', 'Buchungstag',
        #                              'Betrag', 'PaymentReference',
        #                              'PartnerName']  # , 'Buchungstext', 'Beguenstigter', 'Verwendungszweck']
        self.tot_val_of_planned_expenses__ = None
        self.tot_val_of_real_expenses__ = None
        self.tot_val_of_real_income__ = None
        self.tot_val_of_planned_income__ = None
        self.conto__ = 'all'
        self.hideintercontotrans__ = True
        self.month__ = 'month'
        self.year__ = 2026
        self.yearly_all = yearly_all
        self.id_users = id_users
        try:
            self.dataBase = chelt_db
        except Exception as err:
            print(traceback.format_exc())
        CheckCheltRequiredFiles(self.dataBase, self.yearly_all)

    @property
    def myContos(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        return list(set(self.yearly_all.returnColumn('myconto')))

    @property
    def yearly_available_dates(self):
        matches = [('id_users', self.id_users),
                   ('expenses', 'real_expenses')]
        available_years = list(set(self.yearly_all.returnCellsWhere('db_update', matches)))
        min_year = min(available_years)
        max_year = max(available_years)
        months = ['January', 'February', 'March', 'April', 'May', 'June',
                  'July', 'August', 'September', 'October', 'November', 'December']
        all_dates = []
        for year in range(min_year, max_year + 1):
            # print('---year', year)
            for month in months:
                # print('\t---month', month)
                matches = [('id_users', self.id_users), ('db_update', year),
                           ('expenses', 'real_expenses'), ('myconto', 'all'), ('category', 'all')]
                value = self.yearly_all.returnCellsWhere(month, matches)[0]

                if value:
                    ab, bis = get_monthly_interval(month, year)
                    all_dates.append(ab)
                    all_dates.append(bis)
        min_monthly_interval = min(all_dates)
        max_monthly_interval = max(all_dates)

        buchungs_min_max = {}
        # all_contos = list(set(self.imported_csv.returnColumn('banca')))
        for con in self.myContos:
            buchungs_min_max[con] = [min_monthly_interval, max_monthly_interval]
        return buchungs_min_max

    @property
    def categories(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        all_cat = list(set(self.yearly_all.returnColumn('category')))
        # all_cat = [s.lower() for s in all_cat if s is not None]
        return all_cat

    @property
    def all_year_months(self):
        # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
        index_january = self.yearly_all.columnsNames.index('January')
        return self.yearly_all.columnsNames[index_january:]

    @property
    def month(self):
        return self.month__

    @month.setter
    def month(self, val: str):
        self.month__ = val

    @property
    def year(self):
        return self.year__

    @year.setter
    def year(self, val: int):
        self.year__ = val

    @property
    def conto(self):
        return self.conto__

    @conto.setter
    def conto(self, val: str):
        self.conto__ = val

    @property
    def hideintercontotrans(self):
        return self.hideintercontotrans__

    @hideintercontotrans.setter
    def hideintercontotrans(self, val: bool):
        self.hideintercontotrans__ = val

    @property
    def tot_val_of_planned_expenses(self):
        return self.tot_val_of_planned_expenses__

    @tot_val_of_planned_expenses.setter
    def tot_val_of_planned_expenses(self, val: float):
        self.tot_val_of_planned_expenses__ = val

    @property
    def tot_val_of_real_expenses(self):
        return self.tot_val_of_real_expenses__

    @tot_val_of_real_expenses.setter
    def tot_val_of_real_expenses(self, val: float):
        self.tot_val_of_real_expenses__ = val

    @property
    def tot_val_of_real_income(self):
        return self.tot_val_of_real_income__

    @tot_val_of_real_income.setter
    def tot_val_of_real_income(self, val: float):
        self.tot_val_of_real_income__ = val

    @property
    def tot_val_of_planned_income(self):
        return self.tot_val_of_planned_income__

    @tot_val_of_planned_income.setter
    def tot_val_of_planned_income(self, val: float):
        self.tot_val_of_planned_income__ = val

    @property
    def planned_expenses_per_conto(self):
        return self.planned_expenses_per_conto__

    @planned_expenses_per_conto.setter
    def planned_expenses_per_conto(self, val: float):
        self.planned_expenses_per_conto__ = val

    @property
    def planned_income_per_conto(self):
        return self.planned_income_per_conto__

    @planned_income_per_conto.setter
    def planned_income_per_conto(self, val: float):
        self.planned_income_per_conto__ = val

    @property
    def real_expenses_per_conto(self):
        return self.real_expenses_per_conto__

    @real_expenses_per_conto.setter
    def real_expenses_per_conto(self, val: float):
        self.real_expenses_per_conto__ = val

    @property
    def real_income_per_conto(self):
        return self.real_income_per_conto__

    @real_income_per_conto.setter
    def real_income_per_conto(self, val: float):
        self.real_income_per_conto__ = val

    @property
    def planned_expenses_per_category(self):
        return self.planned_expenses_per_category__

    @planned_expenses_per_category.setter
    def planned_expenses_per_category(self, val: float):
        self.planned_expenses_per_category__ = val

    @property
    def real_expenses_per_category(self):
        return self.real_expenses_per_category__

    @real_expenses_per_category.setter
    def real_expenses_per_category(self, val: float):
        self.real_expenses_per_category__ = val

    @property
    def real_income_per_category(self):
        return self.real_income_per_category__

    @real_income_per_category.setter
    def real_income_per_category(self, val: float):
        self.real_income_per_category__ = val

    @property
    def planned_income_per_category(self):
        return self.planned_income_per_category__

    @planned_income_per_category.setter
    def planned_income_per_category(self, val: float):
        self.planned_income_per_category__ = val

    @property
    def planned_expenses_average(self):
        return self.planned_expenses_average__

    @planned_expenses_average.setter
    def planned_expenses_average(self, val: float):
        self.planned_expenses_average__ = val

    @property
    def real_expenses_average(self):
        return self.real_expenses_average__

    @real_expenses_average.setter
    def real_expenses_average(self, val: float):
        self.real_expenses_average__ = val

    @property
    def real_income_average(self):
        return self.real_income_average__

    @real_income_average.setter
    def real_income_average(self, val: float):
        self.real_income_average__ = val

    @property
    def planned_income_average(self):
        return self.planned_income_average__

    @planned_income_average.setter
    def planned_income_average(self, val: float):
        self.planned_income_average__ = val

    @property
    def planned_expenses_per_conto_per_month(self):
        return self.planned_expenses_per_conto_per_month__

    @planned_expenses_per_conto_per_month.setter
    def planned_expenses_per_conto_per_month(self, val: float):
        self.planned_expenses_per_conto_per_month__ = val

    @property
    def real_expenses_per_conto_per_month(self):
        return self.real_expenses_per_conto_per_month__

    @real_expenses_per_conto_per_month.setter
    def real_expenses_per_conto_per_month(self, val: float):
        self.real_expenses_per_conto_per_month__ = val

    @property
    def real_income_per_conto_per_month(self):
        return self.real_income_per_conto_per_month__

    @real_income_per_conto_per_month.setter
    def real_income_per_conto_per_month(self, val: float):
        self.real_income_per_conto_per_month__ = val

    @property
    def planned_income_per_conto_per_month(self):
        return self.planned_income_per_conto_per_month__

    @planned_income_per_conto_per_month.setter
    def planned_income_per_conto_per_month(self, val: float):
        self.planned_income_per_conto_per_month__ = val

    @property
    def planned_expenses_per_category_per_month(self):
        return self.planned_expenses_per_category_per_month__

    @planned_expenses_per_category_per_month.setter
    def planned_expenses_per_category_per_month(self, val: float):
        self.planned_expenses_per_category_per_month__ = val

    @property
    def real_expenses_per_category_per_month(self):
        return self.real_expenses_per_category_per_month__

    @real_expenses_per_category_per_month.setter
    def real_expenses_per_category_per_month(self, val: float):
        self.real_expenses_per_category_per_month__ = val

    @property
    def real_income_per_category_per_month(self):
        return self.real_income_per_category_per_month__

    @real_income_per_category_per_month.setter
    def real_income_per_category_per_month(self, val: float):
        self.real_income_per_category_per_month__ = val

    @property
    def planned_income_per_category_per_month(self):
        return self.planned_income_per_category_per_month__

    @planned_income_per_category_per_month.setter
    def planned_income_per_category_per_month(self, val: float):
        self.planned_income_per_category_per_month__ = val

    def get_monthly_values(self, expenses_type):
        try:
            category = 'all'
            matches = [('id_users', self.id_users),
                       ('db_update', self.year),
                       ('expenses', expenses_type),
                       ('myconto', self.conto),
                       ('category', category)]
            value = self.yearly_all.returnCellsWhere(self.month, matches)[0]
            if self.hideintercontotrans:
                matches_intercontotrans = [('id_users', self.id_users),
                                           ('db_update', self.year),
                                           ('expenses', expenses_type),
                                           ('myconto', self.conto),
                                           ('category', 'intercontotrans')]
                value_intercontotrans = self.yearly_all.returnCellsWhere(self.month, matches_intercontotrans)
                if value and value_intercontotrans:
                    value = value - value_intercontotrans[0]
            return value
        except:
            print('ÖÖÖÖÖmatches', matches)
            print(traceback.format_exc())
            return None

    def get_monthly_values_per_conto(self, expenses_type):
        category = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        # matches = [('id_users', self.id_users),
        #            ('db_update', self.year),
        #            ('expenses', expenses_type)]
        # all_contos = self.yearly_all.returnCellsWhere('myconto', matches)
        # all_contos = list(set(all_contos))
        pl_expenses_per_conto = {}
        for conto in self.myContos:
            matches = [('id_users', self.id_users),
                       ('db_update', self.year),
                       ('expenses', expenses_type),
                       ('myconto', conto),
                       ('category', category)]
            try:
                value = self.yearly_all.returnCellsWhere(self.month, matches)[0]
            except:
                # print('+++++++matchesconto', matches)
                value = 0
                pl_expenses_per_conto[conto] = value
                continue

            if self.hideintercontotrans:
                matches_intercontotrans = [('id_users', self.id_users),
                                           ('db_update', self.year),
                                           ('expenses', expenses_type),
                                           ('myconto', conto),
                                           ('category', 'intercontotrans')]
                value_intercontotrans = self.yearly_all.returnCellsWhere(self.month, matches_intercontotrans)
                if value and value_intercontotrans:
                    if value_intercontotrans[0] is None:
                        value_intercontotrans[0] = 0
                    value = value - value_intercontotrans[0]
                pl_expenses_per_conto[conto] = value
        pl_expenses_per_conto = dict(sorted(pl_expenses_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_conto

    def get_monthly_values_per_category(self, expenses_type):
        conto = 'all'
        # index_january = self.yearly_all.columnsNames.index('January')
        # matches = [('id_users', self.id_users),
        #            ('db_update', self.year),
        #            ('expenses', expenses_type)]
        # all_categories = self.yearly_all.returnCellsWhere('category', matches)
        # all_categories = list(set(all_categories))
        pl_expenses_per_categories = {}
        for category in self.categories:
            matches = [('id_users', self.id_users),
                       ('db_update', self.year),
                       ('expenses', expenses_type),
                       ('myconto', conto),
                       ('category', category)]
            try:
                value = self.yearly_all.returnCellsWhere(self.month, matches)[0]
                pl_expenses_per_categories[category] = value
            except:
                # print('*****matches', matches)
                value = 0
                pl_expenses_per_categories[category] = value
                continue
        if self.hideintercontotrans:
            pl_expenses_per_categories['all'] = pl_expenses_per_categories['all'] - pl_expenses_per_categories['intercontotrans']

            del pl_expenses_per_categories["intercontotrans"]
        pl_expenses_per_categories = dict(
            sorted(pl_expenses_per_categories.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_categories

    def get_yearly_values(self, expenses_type, category='all', ):
        try:
            index_january = self.yearly_all.columnsNames.index('January')
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', self.year),
                       ('expenses', '=', expenses_type),
                       ('myconto', '=', self.conto),
                       ('category', '=', category)]
            row = self.yearly_all.returnRowsQuery(matches)[0]
            value = row[index_january:]
            # value = [x for x in value if x is not None]
            value = [0 if v is None else v for v in value]
            # print('++++sum(value)', sum(value))
            if self.hideintercontotrans:
                matches_intercontotrans = [('id_users', '=', self.id_users),
                                           ('db_update', '=', self.year),
                                           ('expenses', '=', expenses_type),
                                           ('myconto', '=', self.conto),
                                           ('category', '=', 'intercontotrans')]
                row_intercontotrans = self.yearly_all.returnRowsQuery(matches_intercontotrans)
                if row_intercontotrans:
                    row_intercontotrans = row_intercontotrans[0]
                    value_intercontotrans = row_intercontotrans[index_january:]
                    # value_intercontotrans = [x for x in value_intercontotrans if x is not None]
                    value_intercontotrans = [0 if v is None else v for v in value_intercontotrans]
                    # value_intercontotrans = sum(value_intercontotrans)
                else:
                    value_intercontotrans = 0
                if value and value_intercontotrans:
                    value = np.array(value) - np.array(value_intercontotrans)
            # print('KKKKKKvalue', value, type(value))
            return list(value)
        except:
            print(traceback.format_exc())
            return None

    def get_yearly_values_per_conto(self, expenses_type):
        category = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        pl_expenses_per_conto = {}
        for conto in self.myContos:
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', self.year),
                       ('expenses', '=', expenses_type),
                       ('myconto', '=', conto),
                       ('category', '=', category)]
            try:
                row = self.yearly_all.returnRowsQuery(matches)[0]
            except:
                # print('####*****contomatches', matches)
                value = np.arange(12, dtype=object)
                pl_expenses_per_conto[conto] = list(value)
                continue
            value = row[index_january:]
            value = np.array([0 if v is None else v for v in value], dtype=object)

            if self.hideintercontotrans:
                matches_intercontotrans = [('id_users', '=', self.id_users),
                                           ('db_update', '=', self.year),
                                           ('expenses', '=', expenses_type),
                                           ('myconto', '=', conto),
                                           ('category', '=', 'intercontotrans')]

                row_intercontotrans = self.yearly_all.returnRowsQuery(matches_intercontotrans)
                if row_intercontotrans:
                    row_intercontotrans = row_intercontotrans[0]
                    value_intercontotrans = row_intercontotrans[index_january:]
                    # value_intercontotrans = [x for x in value_intercontotrans if x is not None]
                    value_intercontotrans = np.array([0 if v is None else v for v in value_intercontotrans],
                                                     dtype=object)
                    # value_intercontotrans = sum(value_intercontotrans)
                else:
                    value_intercontotrans = None
                if value is not None and value_intercontotrans is not None:
                    value = value - value_intercontotrans
                pl_expenses_per_conto[conto] = list(value)

        pl_expenses_per_conto = dict(sorted(pl_expenses_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_conto

    def get_yearly_sum_per_conto(self, expenses_type):
        category = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        pl_expenses_per_conto = {}
        for conto in self.myContos:
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', self.year),
                       ('expenses', '=', expenses_type),
                       ('myconto', '=', conto),
                       ('category', '=', category)]
            try:
                row = self.yearly_all.returnRowsQuery(matches)[0]
            except:
                # print('####*****contomatches', matches)
                value = 0
                pl_expenses_per_conto[conto] = value
                continue
            value = row[index_january:]
            value = [x for x in value if x is not None]
            value = sum(value)
            if self.hideintercontotrans:
                matches_intercontotrans = [('id_users', '=', self.id_users),
                                           ('db_update', '=', self.year),
                                           ('expenses', '=', expenses_type),
                                           ('myconto', '=', conto),
                                           ('category', '=', 'intercontotrans')]

                row_intercontotrans = self.yearly_all.returnRowsQuery(matches_intercontotrans)
                if row_intercontotrans:
                    row_intercontotrans = row_intercontotrans[0]
                    value_intercontotrans = row_intercontotrans[index_january:]
                    value_intercontotrans = [x for x in value_intercontotrans if x is not None]
                    value_intercontotrans = sum(value_intercontotrans)
                else:
                    value_intercontotrans = 0
                if value and value_intercontotrans:
                    value = value - value_intercontotrans
                pl_expenses_per_conto[conto] = value

        pl_expenses_per_conto = dict(sorted(pl_expenses_per_conto.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_conto

    def get_yearly_sum_per_category(self, expenses_type):
        conto = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        # matches = [('id_users', self.id_users),
        #            ('db_update', self.year),
        #            ('expenses', expenses_type)]
        # all_categories = self.yearly_all.returnCellsWhere('category', matches)
        # all_categories = list(set(all_categories))
        pl_expenses_per_categories = {}
        # for category in all_categories:
        for category in self.categories:
            if category is None:
                matches = [('id_users', '=', self.id_users),
                           ('db_update', '=', self.year),
                           ('expenses', '=', expenses_type),
                           ('myconto', '=', conto),
                           ('category', 'IS', category)]
            else:
                matches = [('id_users', '=', self.id_users),
                           ('db_update', '=', self.year),
                           ('expenses', '=', expenses_type),
                           ('myconto', '=', conto),
                           ('category', '=', category)]
            try:
                row = self.yearly_all.returnRowsQuery(matches)[0]
            except:
                # print('####matches', matches)
                value = 0
                pl_expenses_per_categories[category] = value
                continue
            value = row[index_january:]
            value = [x for x in value if x is not None]
            value = sum(value)
            # if self.hideintercontotrans:
            #     matches_intercontotrans = [('id_users', '=', self.id_users),
            #                                ('db_update', '=', self.year),
            #                                ('expenses', '=', 'planned_expenses'),
            #                                ('myconto', '=', conto),
            #                                ('category', '=', 'intercontotrans')]
            #     row_intercontotrans = self.yearly_all.returnRowsQuery(matches_intercontotrans)[0]
            #     value_intercontotrans = row_intercontotrans[index_january:]
            #     value_intercontotrans = [x for x in value_intercontotrans if x is not None]
            #     value_intercontotrans = sum(value_intercontotrans)
            #     if value and value_intercontotrans:
            #         value = value - value_intercontotrans
            pl_expenses_per_categories[category] = value
        pl_expenses_per_categories = dict(
            sorted(pl_expenses_per_categories.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_categories

    def get_yearly_values_per_category(self, expenses_type):
        conto = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        pl_expenses_per_categories = {}
        for category in self.categories:
            if category is None:
                matches = [('id_users', '=', self.id_users),
                           ('db_update', '=', self.year),
                           ('expenses', '=', expenses_type),
                           ('myconto', '=', conto),
                           ('category', 'IS', category)]
            else:
                matches = [('id_users', '=', self.id_users),
                           ('db_update', '=', self.year),
                           ('expenses', '=', expenses_type),
                           ('myconto', '=', conto),
                           ('category', '=', category)]
            try:
                row = self.yearly_all.returnRowsQuery(matches)[0]
            except:
                # print('####matches', matches)
                value = np.arange(12, dtype=object)
                pl_expenses_per_categories[category] = list(value)
                continue
            value = row[index_january:]
            value = np.array([0 if v is None else v for v in value], dtype=object)
            pl_expenses_per_categories[category] = value
        pl_expenses_per_categories = dict(
            sorted(pl_expenses_per_categories.items(), key=lambda item: (item[0] is None, item[0])))
        return pl_expenses_per_categories

    def get_yearly_average(self, expenses_type):
        monthly_average_per_conto = {}
        category = 'all'
        index_january = self.yearly_all.columnsNames.index('January')
        matches = [('id_users', '=', self.id_users),
                   ('db_update', '=', self.year),
                   ('expenses', '=', expenses_type),
                   ('category', '=', category)]
        all_rows = self.yearly_all.returnRowsQuery(matches)
        for row in all_rows:
            conto = row[self.yearly_all.columnsNames.index('myconto')]
            monthly_values = row[index_january:]
            sum_monthly_values = sum([x for x in monthly_values if x])
            # monthly_average = sum(monthly_values) / 12
            # print('ääääärow', row)
            # print('ääääämonthly_values', monthly_values)
            # print('äääääconto', conto)
            # print()
            matches = [('id_users', '=', self.id_users),
                       ('db_update', '=', self.year),
                       ('expenses', '=', expenses_type),
                       ('myconto', '=', conto),
                       ('category', '=', 'intercontotrans')]

            intercontotrans = self.yearly_all.returnRowsQuery(matches)
            if intercontotrans:
                intercontotrans = intercontotrans[0]
                intercontotrans_values = intercontotrans[index_january:]
                sum_intercontotrans_values = sum([x for x in intercontotrans_values if x])
            else:
                sum_intercontotrans_values = 0
            monthly_average = (sum_monthly_values - sum_intercontotrans_values) / 12
            monthly_average_per_conto[conto] = round(monthly_average, 2)
        return monthly_average_per_conto

    def prepareTablePlan(self):
        expenses_types = ['planned_expenses', 'real_expenses', 'real_income', 'planned_income']
        if self.month == 'month':
            for exp_type in expenses_types:
                if exp_type == 'planned_expenses':
                    yearly_value = self.get_yearly_values(exp_type)
                    if yearly_value:
                        self.tot_val_of_planned_expenses = sum(yearly_value)
                    else:
                        self.tot_val_of_planned_expenses = yearly_value
                    self.planned_expenses_per_conto = self.get_yearly_sum_per_conto(exp_type)
                    self.planned_expenses_per_conto_per_month = self.get_yearly_values_per_conto(exp_type)
                    self.planned_expenses_per_category = self.get_yearly_sum_per_category(exp_type)
                    self.planned_expenses_per_category_per_month = self.get_yearly_values_per_category(exp_type)
                    self.planned_expenses_average = self.get_yearly_average(exp_type)
                elif exp_type == 'real_expenses':
                    yearly_value = self.get_yearly_values(exp_type)
                    if yearly_value:
                        self.tot_val_of_real_expenses = sum(yearly_value)
                    else:
                        self.tot_val_of_planned_expenses = yearly_value
                    self.real_expenses_per_conto = self.get_yearly_sum_per_conto(exp_type)
                    self.real_expenses_per_conto_per_month = self.get_yearly_values_per_conto(exp_type)
                    self.real_expenses_per_category = self.get_yearly_sum_per_category(exp_type)
                    self.real_expenses_per_category_per_month = self.get_yearly_values_per_category(exp_type)
                    self.real_expenses_average = self.get_yearly_average(exp_type)
                elif exp_type == 'real_income':
                    yearly_value = self.get_yearly_values(exp_type)
                    if yearly_value:
                        self.tot_val_of_real_income = sum(yearly_value)
                    else:
                        self.tot_val_of_planned_expenses = yearly_value
                    self.real_income_per_conto = self.get_yearly_sum_per_conto(exp_type)
                    self.real_income_per_conto_per_month = self.get_yearly_values_per_conto(exp_type)
                    self.real_income_per_category = self.get_yearly_sum_per_category(exp_type)
                    self.real_income_per_category_per_month = self.get_yearly_values_per_category(exp_type)
                    self.real_income_average = self.get_yearly_average(exp_type)
                elif exp_type == 'planned_income':
                    yearly_value = self.get_yearly_values(exp_type)
                    if yearly_value:
                        self.tot_val_of_planned_income = sum(yearly_value)
                    else:
                        self.tot_val_of_planned_expenses = yearly_value
                    self.planned_income_per_conto = self.get_yearly_sum_per_conto(exp_type)
                    self.planned_income_per_conto_per_month = self.get_yearly_values_per_conto(exp_type)
                    self.planned_income_per_category = self.get_yearly_sum_per_category(exp_type)
                    self.planned_income_per_category_per_month = self.get_yearly_values_per_category(exp_type)
                    self.planned_income_average = self.get_yearly_average(exp_type)
        else:
            for exp_type in expenses_types:
                if exp_type == 'planned_expenses':
                    self.tot_val_of_planned_expenses = self.get_monthly_values(exp_type)
                    self.planned_expenses_per_conto = self.get_monthly_values_per_conto(exp_type)
                    self.planned_expenses_per_conto_per_month = self.get_monthly_values_per_conto(exp_type)
                    self.planned_expenses_per_category = self.get_monthly_values_per_category(exp_type)
                    self.planned_expenses_per_category_per_month = self.get_monthly_values_per_category(exp_type)
                    self.planned_expenses_average = self.get_yearly_average(exp_type)
                elif exp_type == 'real_expenses':
                    self.tot_val_of_real_expenses = self.get_monthly_values(exp_type)
                    self.real_expenses_per_conto = self.get_monthly_values_per_conto(exp_type)
                    self.real_expenses_per_conto_per_month = self.get_monthly_values_per_conto(exp_type)
                    self.real_expenses_per_category = self.get_monthly_values_per_category(exp_type)
                    self.real_expenses_per_category_per_month = self.get_monthly_values_per_category(exp_type)
                    self.real_expenses_average = self.get_yearly_average(exp_type)
                elif exp_type == 'real_income':
                    # self.tot_val_of_real_income = self.get_tot_val_of_planned_expenses(exp_type)
                    self.tot_val_of_real_income = self.get_monthly_values(exp_type)
                    self.real_income_per_conto = self.get_monthly_values_per_conto(exp_type)
                    self.real_income_per_conto_per_month = self.get_monthly_values_per_conto(exp_type)
                    self.real_income_per_category = self.get_monthly_values_per_category(exp_type)
                    self.real_income_per_category_per_month = self.get_monthly_values_per_category(exp_type)
                    self.real_income_average = self.get_yearly_average(exp_type)
                elif exp_type == 'planned_income':
                    # self.tot_val_of_planned_income = self.get_tot_val_of_planned_expenses(exp_type)
                    self.tot_val_of_planned_income = self.get_monthly_values(exp_type)
                    self.planned_income_per_conto = self.get_monthly_values_per_conto(exp_type)
                    self.planned_income_per_conto_per_month = self.get_monthly_values_per_conto(exp_type)
                    self.planned_income_per_category = self.get_monthly_values_per_category(exp_type)
                    self.planned_income_per_category_per_month = self.get_monthly_values_per_category(exp_type)
                    self.planned_income_average = self.get_yearly_average(exp_type)

    def get_common_categories(self, planned_expenses_per_category_per_month, real_expenses_per_category_per_month):
        if self.month != 'month':
            dicts = [planned_expenses_per_category_per_month, real_expenses_per_category_per_month]
            categories_with_values = []
            for ddd in dicts:
                for cat, value in ddd.items():
                    if value != 0 and value is not None:
                        # print(cat, value)
                        if cat not in categories_with_values:
                            categories_with_values.append(cat)
            # print(categories_with_values)
            new_planned_expenses_per_category_per_month = {}
            for categ, val in planned_expenses_per_category_per_month.items():
                if categ in categories_with_values:
                    new_planned_expenses_per_category_per_month[categ] = val
            new_real_expenses_per_category_per_month = {}
            for categ, val in real_expenses_per_category_per_month.items():
                if categ in categories_with_values:
                    new_real_expenses_per_category_per_month[categ] = val
            result = [new_planned_expenses_per_category_per_month, new_real_expenses_per_category_per_month]
        else:
            raise RuntimeError('not implemented yet')
        return result

    def get_common_categories_new(self, *dictionaries):
        dicts = [*dictionaries]
        categories_with_values = []
        if self.month != 'month':
            for ddd in dicts:
                for cat, value in ddd.items():
                    if value != 0 and value is not None:
                        # print(cat, value)
                        if cat not in categories_with_values:
                            categories_with_values.append(cat)
        else:
            for ddd in dicts:
                for cat, value in ddd.items():
                    # print('ÖÖÖÖvalue', value)
                    if value != 0 and value is not None:
                        if cat not in categories_with_values:
                            categories_with_values.append(cat)

        # print('+++++categories_with_values', categories_with_values)
        list_of_new_dicts = []
        for dict in dictionaries:
            new_dict = {}
            for categ, val in dict.items():
                if categ in categories_with_values:
                    new_dict[categ] = val
            list_of_new_dicts.append(new_dict)
        return list_of_new_dicts

    def get_total_and_average_values_for_time(self, year_before=False):
        values_dict = {'conto': self.conto,
                       'year': self.year,
                       'month': self.month,
                       }
        expenses = {'tot_val_of_planned_expenses': round(self.tot_val_of_planned_expenses, 0),
                    'average_of_planned_expenses': round(self.planned_expenses_average['all'], 0),
                    'tot_val_of_real_expenses': round(self.tot_val_of_real_expenses, 0),
                    'average_val_of_real_expenses': round(self.real_expenses_average['all'], 0),
                    }
        income = {'tot_val_of_planned_income': round(self.tot_val_of_planned_income, 0),
                  'average_val_of_planned_income': round(self.planned_income_average['all'], 0),
                  'tot_val_of_real_income': round(self.tot_val_of_real_income, 0),
                  'average_val_of_real_income': round(self.real_income_average['all'], 0),
                  }
        if year_before:
            self.tot_val_of_real_expenses = None
            self.planned_expenses_average = None
            self.tot_val_of_real_income = None
            self.real_income_average = None
            year_before = self.year - 1
            self.year = year_before
            self.prepareTablePlan()
            if self.tot_val_of_real_expenses:
                expenses['tot_val_of_real_expenses_year_before'] = round(self.tot_val_of_real_expenses, 0)
            else:
                expenses['tot_val_of_real_expenses_year_before'] = None
            if self.real_expenses_average and 'all' in self.real_expenses_average.keys():
                expenses['average_val_of_real_expenses_year_before'] = round(self.real_expenses_average['all'], 0)
            else:
                expenses['average_val_of_real_expenses_year_before'] = None

            if self.tot_val_of_real_income:
                income['tot_val_of_real_income_year_before'] = round(self.tot_val_of_real_income, 0)
            else:
                income['tot_val_of_real_income_year_before'] = None

            if self.real_income_average and 'all' in self.real_income_average.keys():
                income['average_val_of_real_income_year_before'] = round(self.real_income_average['all'], 0)
            else:
                income['average_val_of_real_income_year_before'] = None

        values_dict['expenses'] = expenses
        values_dict['income'] = income
        return values_dict

    # def get_conto_yearly_planned_expenses(self, year=None):
    #     # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     matches = [('id_users', '=', self.id_users),
    #                ('db_update', '=', year),
    #                ('expenses', '=', 'planned_expenses'),
    #                ('category', '=', 'all')
    #                ]
    #     payments4Interval = self.yearly_all.returnRowsQuery(matches)
    #     index_january = self.yearly_all.columnsNames.index('January')
    #     labels = self.yearly_all.columnsNames[index_january:]
    #     payments_dict = {}
    #     for row in payments4Interval:
    #         # print('row****', row)
    #         my_conto = row[self.yearly_all.columnsNames.index('myconto')]
    #         # if my_conto == 'all':
    #         #     continue
    #         vals = []
    #         for val in row[index_january:]:
    #             if val is None:
    #                 vals.append(val)
    #                 continue
    #             vals.append(float(val))
    #         payments_dict[my_conto] = vals
    #     sorted_payments_dict = dict(sorted(payments_dict.items(), key=lambda item: item[0]))
    #     return sorted_payments_dict, labels
    #
    # def get_conto_yearly_planned_income(self, year=None):
    #     # print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name, sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     matches = [('id_users', '=', self.id_users),
    #                ('db_update', '=', year),
    #                ('expenses', '=', 'planned_income'),
    #                ('category', '=', 'all')
    #                ]
    #     payments4Interval = self.yearly_all.returnRowsQuery(matches)
    #     index_january = self.yearly_all.columnsNames.index('January')
    #     labels = self.yearly_all.columnsNames[index_january:]
    #     payments_dict = {}
    #     for row in payments4Interval:
    #         # print('row****', row)
    #         my_conto = row[self.yearly_all.columnsNames.index('myconto')]
    #         # if my_conto == 'all':
    #         #     continue
    #         vals = []
    #         for val in row[index_january:]:
    #             if val is None:
    #                 vals.append(val)
    #                 continue
    #             vals.append(float(val))
    #         payments_dict[my_conto] = vals
    #     sorted_payments_dict = dict(sorted(payments_dict.items(), key=lambda item: item[0]))
    #     return sorted_payments_dict, labels
    #
    # def get_conto_yearly_real_expenses(self, year=None):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     matches = [('id_users', '=', self.id_users),
    #                ('db_update', '=', year),
    #                ('expenses', '=', 'real_expenses'),
    #                ('category', '=', 'all')
    #                ]
    #     payments4Interval = self.yearly_all.returnRowsQuery(matches)
    #     index_january = self.yearly_all.columnsNames.index('January')
    #     labels = self.yearly_all.columnsNames[index_january:]
    #     payments_dict = {}
    #     for row in payments4Interval:
    #         # print('KKKKKrow', row)
    #         my_conto = row[self.yearly_all.columnsNames.index('myconto')]
    #         # if my_conto == 'all':
    #         #     continue
    #         vals = []
    #         for val in row[index_january:]:
    #             if val:
    #                 vals.append(float(val))
    #             else:
    #                 vals.append(0)
    #         payments_dict[my_conto] = vals
    #     sorted_real_payments_dict = dict(sorted(payments_dict.items(), key=lambda item: item[0]))
    #     return sorted_real_payments_dict, labels
    #
    # def get_conto_yearly_real_income(self, year=None):
    #     #        #print('Module: {}, Class: {}, Def: {}, Caller: {}'.format(__name__, __class__, sys._getframe().f_code.co_name,
    #     #                                                                  sys._getframe().f_back.f_code.co_name))
    #     if not year:
    #         year = datetime.now().year
    #     matches = [('id_users', '=', self.id_users),
    #                ('db_update', '=', year),
    #                ('expenses', '=', 'real_income'),
    #                ('category', '=', 'all')
    #                ]
    #     payments4Interval = self.yearly_all.returnRowsQuery(matches)
    #     index_january = self.yearly_all.columnsNames.index('January')
    #     labels = self.yearly_all.columnsNames[index_january:]
    #     payments_dict = {}
    #     for row in payments4Interval:
    #         # print('KKKKKrow', row)
    #         my_conto = row[self.yearly_all.columnsNames.index('myconto')]
    #         # if my_conto == 'all':
    #         #     continue
    #         vals = []
    #         for val in row[index_january:]:
    #             if val:
    #                 vals.append(float(val))
    #             else:
    #                 vals.append(0)
    #         payments_dict[my_conto] = vals
    #     return payments_dict, labels


def chelt_app(user_id, chelt_db):
    # user_id, chelt_db, chelt_plan, yearly_plan
    cheltapp = CheltApp(user_id=user_id,
                        chelt_db=chelt_db,
                        chelt_plan=chelt_db.chelt_plan,
                        yearly_plan=chelt_db.yearly_plan,
                        imported_csv=chelt_db.imported_csv,
                        )
    # #print(cheltapp.has_cheltuieli_planned)
    # print('cheltapp.backup_profile_dir', cheltapp.backup_profile_dir)
    # print('cheltapp.last_profile_backup', cheltapp.last_profile_backup)
    # print('cheltapp.last_profile_backup', cheltapp.last_profile_backup)

    # print('cheltapp.backup_income_plan_dir', cheltapp.backup_income_plan_dir)
    # print('cheltapp.last_income_plan_backup', cheltapp.last_income_plan_backup)
    # print('cheltapp.last_income_plan_backup_file', cheltapp.last_income_plan_backup_file)
    # cheltapp.export_real_expenses_csvs()


def cheltuieli_planificate(chelt_db_connection, conto, selectedStartDate, selectedEndDate, id_users):
    app_planned = CheltuieliPlanificate(chelt_db=chelt_db_connection.chelt_db,
                                        chelt_plan=chelt_db_connection.chelt_plan,
                                        yearly_plan=chelt_db_connection.yearly_plan,
                                        yearly_all=chelt_db_connection.yearly_all,
                                        id_users=id_users
                                        )

    app_planned.prepareTablePlan(conto=conto,
                                 selectedStartDate=selectedStartDate, selectedEndDate=selectedEndDate,
                                 hideintercontotrans=False)
    # for rr in app_planned.expenses:
    #     print(rr)
    # app_planned.write_sql_yearly_plan(year=2025)
    app_planned.write_planned_income_yearly_all(year=2026, write_to_sql=True)
    print('app_planned.tot_val_of_expenses', app_planned.tot_val_of_expenses)
    print('app_planned.tot_val_of_monthly_expenses', app_planned.tot_val_of_monthly_expenses)
    print('app_planned.tot_val_of_irregular_expenses', app_planned.tot_val_of_irregular_expenses)
    print('app_planned.totals_summary', app_planned.totals_summary)
    print('app_planned.expenses_per_conto', app_planned.expenses_per_conto)
    print('app_planned.expenses_per_category', app_planned.expenses_per_category)
    print('app_planned.expenses_per_names', app_planned.expenses_per_names)
    print('app_planned.expenses_per_conto_per_category', app_planned.expenses_per_conto_per_category)
    print('app_planned.all_planned_values', app_planned.all_planned_values)
    print('app_planned.tot_val_of_income', app_planned.tot_val_of_income)
    print(100 * '#')
    print()
    # for k, v in app_planned.expenses_per_conto_per_category.items():
    #     print(k, v)
    # app_planned.write_sql_yearly_all(year=2025, write_to_sql=True)

    # payments_dict, labels = app_planned.prep_yearly_graf(year=2026)
    # if not payments_dict:
    #     print('NO yearly table')
    # else:
    #     for k, v in payments_dict.items():
    #         print(k, v)
    # print()
    # payments_dict, labels = app_planned.prep_conto_yearly_graf(2025)
    # if not payments_dict:
    #     print('NO yearly table')
    # else:
    #     for k, v in payments_dict.items():
    #         print(k, v)
    print()
    # for rr in app_planned.totals_per_conto.items():
    #     print(rr)
    # # tableHead, table = convert_to_display_table(app_planned.tableHead,
    #                                                        app_planned.expenses,
    #                                                        app_planned.displayExpensesTableHead)
    # for ii in table:
    #     #print(ii)
    # #print(tableHead)
    # app_planned.copy_chelt_plan_row(2)
    # payments_dict, labels = app_planned.prep_yearly_graf()
    # print(payments_dict)
    # print(labels)


def app_income(chelt_db_connection, conto, selectedStartDate, selectedEndDate):
    app_income = Income(income_table=chelt_db_connection.income_table)
    app_income.prepareTablePlan(conto, selectedStartDate, selectedEndDate)
    # print('income.netto', app_income.netto)
    # print('income.brutto', app_income.brutto)
    # print('income.salary_uberweisung', app_income.salary_uberweisung)
    # print('income.salary_abzuge', app_income.salary_abzuge)
    # print('income.salary_netto', app_income.salary_netto)
    # print('income.salary_gesetzliche_abzuge', app_income.salary_gesetzliche_abzuge)
    # print('income.salary_brutto', app_income.salary_brutto)
    # print('income.monthly_income', app_income.monthly_income)

    # print(app_income.tableHead)
    # for ii in app_income.income:
    #     #print(ii)


def app_reale(chelt_db_connection, conto, selectedStartDate, selectedEndDate, id_users):
    app_reale = CheltuieliReale(chelt_db=chelt_db_connection.chelt_db,
                                myAccountsTable=chelt_db_connection.myAccountsTable,
                                imported_csv=chelt_db_connection.imported_csv,
                                chelt_plan=chelt_db_connection.chelt_plan,
                                plan_vs_real=chelt_db_connection.plan_vs_real,
                                knowntrans=chelt_db_connection.knowntrans,
                                sskm=chelt_db_connection.sskm,
                                deubnk=chelt_db_connection.deubnk,
                                n26=chelt_db_connection.n26,
                                yearly_all=chelt_db_connection.yearly_all,
                                id_users=id_users)
    # print(app_reale.default_interval())
    print(app_reale.last_month_of_last_csv())
    return

    app_reale.prepareTableReal_new(currentConto=conto, selectedStartDate=selectedStartDate,
                                   selectedEndDate=selectedEndDate, hideIntercontotrans=True)
    # print('app_reale.expenses_per_conto_per_category', app_reale.expenses_per_conto_per_category)
    # app_reale.write_real_yearly_all(write_to_sql=True)
    print('app_reale.imported_csv_dates', app_reale.imported_csv_dates)
    print('app_reale.yearly_available_dates', app_reale.yearly_available_dates)
    # for k, v in app_reale.expenses_per_conto_per_category.items():
    #     tot_val, no_of_transactions, totals_per_category = v
    #     print(k, tot_val, no_of_transactions)
    #     for kk, vv in totals_per_category.items():
    #         print('\t', kk, vv)

    print('app_reale.tot_val_of_expenses', app_reale.tot_val_of_expenses)
    print('app_reale.expenses_per_conto', app_reale.expenses_per_conto)
    # print('app_reale.tot_val_of_irregular_expenses', app_reale.tot_val_of_irregular_expenses)
    # print('app_reale.totals_summary', app_reale.totals_summary)
    print('app_reale.total_income_minus_expenses_per_conto', app_reale.total_income_minus_expenses_per_conto)
    print('app_reale.expenses_per_category', app_reale.expenses_per_category)
    # print('app_reale.expenses_per_names', app_reale.expenses_per_names)

    # print('app_reale.all_planned_values', app_reale.all_planned_values)
    # print('app_reale.tot_val_of_income', app_reale.tot_val_of_income)

    # for rr in app_reale.realExpenses:
    #     print('ÖÖÖrr', rr)
    # print(app_reale.realExpenses.shape)
    # print(app_reale.tot_val_of_expenses)

    # print(app_reale.imported_csv_dates)
    # print('app_reale.expenses_per_category', app_reale.expenses_per_category)
    # app_reale.write_real_expenses_yearly_all()
    # print('app_reale.expenses_per_conto_per_category')#, app_reale.expenses_per_conto_per_category
    # print('app_reale.income_per_conto_per_category')#, app_reale.expenses_per_conto_per_category
    # for k, v in app_reale.income_per_conto_per_category.items():
    #     print(k, v)

    # app_reale.write_real_income_yearly_all_new(write_to_sql=True)
    # nonUniqArray = app_reale.returnRowsFromTable_plan_vs_real_where_same_bank_table_and_id_bank_table()
    # for rr in nonUniqArray:
    #     print('ÖÖÖÖ', rr)
    # notINplan_vs_real = app_reale.get_unplanned_chelt_from_bank_table(currentConto='all',
    #                                                                   selectedStartDate=selectedStartDate,
    #                                                                   selectedEndDate=selectedEndDate)
    # values = app_reale.vals_for_grafik(app_reale.imported_csv_dates, selectedStartDate, selectedEndDate)
    # for row, (bank, interval) in enumerate(values.items()):
    #     print(bank, interval)
    # db_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\DeutschBank\Transactions_220_5526959_00_20251117_162918.csv"
    # db_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\DeutschBank\Transactions_220_5526959_00_20251001_074838.csv"
    # db_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\2025\Transactions_220_5526959_00_20260109_182113.csv"
    # db_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\DeutscheBank\Kontoumsaetze_220_552695900_20250718_173426.csv"
    # db_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\DeutscheBank\Transactions_220_552695900_20250504_155510.csv"
    # n26_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\N26\N26\n26-csv-transactions.csv"
    # n26_csv = r"C:\_Development\Diverse\pypi\rappmysql\dist\csvs\N26\N26\Main Account 2025-09-01-2025.11.17.csv"
    # csvs = r"D:\Python\MySQL\myrappsql\src\rappmysql\cheltuieli\static\backup_profile\000000001\real_expenses\2026_01_14__06_55_49_000000001\2026_01_14__06_55_49_000000001"
    # table_head, csv_tabel_cheltuieli = app_reale.check_csv_table_head(n26_csv, 'N26')
    # for rr in app_reale.realExpenses:
    #     print('ÖÖÖrr', rr)
    # print(app_reale.realExpenses.shape)
    # print('table_headrr', table_head)
    # print('app_reale.totals_per_conto', app_reale.totals_per_conto)
    # print('app_reale.expenses_per_conto', app_reale.expenses_per_conto)
    # print('app_reale.income_per_conto', app_reale.income_per_conto)
    # print('len(table_head)', len(table_head))
    # app_reale.import_CSV_new('DeutscheBank', db_csv)
    # app_reale.find_chelt_plan_rows_in_banks_tables_and_write_to_plan_vs_real_table()
    # res = app_reale.returnNonUniqRows('DeutscheBank', ['Buchungstag', 'Debit', 'Credit'])
    # for ii in res:
    #     print(ii)_
    # src = r'C:\_Development\Diverse\pypi\rappmysql\src\rappmysql\cheltuieli\static\backup_profile\000000001\real_expenses\2026_01_13__15_21_49_000000001'
    # app_reale.import_profile_bank_all_csvs(src)
    # app_reale.import_CSV_new('EC', EC_csv)
    # app_reale.import_real_expenses_csvs()
    # print(app_reale.expenses_per_conto)
    # print(app_reale.expenses_per_conto)
    # print(app_reale.write_real_income_yearly_all(2025))
    # payments_dict, labels = app_reale.prep_real_expenses_yearly_graf(2025)
    # payments_dict, labels = app_reale.prep_real_income_yearly_graf(2025)
    # print(payments_dict, labels)
    # app_reale.import_profile_bank_all_csvs(csvs)
    # app_reale.names_values4pie()
    # source_table = 'chelt_plan'
    # app_reale.check_1_row_from_chelt_plan_knowntrans(source_table=source_table, row_id=188, write_in_real_table=False)
    # app_reale.find_all_rows_with_identifications_and_write_to_plan_vs_real_table()
    # app_reale.reset_plan_vs_real()
    # app_reale.check_1_row_from_chelt_plan(row_id=188, write_in_real_table=False)
    # ids = (20092, 20094)
    # app_reale.delete_from_plan_vs_real_and_id_from_bank_table(ids_plan_vs_real=ids)


def app_planvsReal(chelt_db_connection, conto, selectedStartDate, selectedEndDate):
    planvsReal = CheltPlanVSReal(chelt_db=chelt_db_connection.chelt_db,
                                 chelt_plan=chelt_db_connection.chelt_plan,
                                 yearly_plan=chelt_db_connection.yearly_plan,
                                 myAccountsTable=chelt_db_connection.myAccountsTable,
                                 imported_csv=chelt_db_connection.imported_csv,
                                 plan_vs_real=chelt_db_connection.plan_vs_real,
                                 knowntrans=chelt_db_connection.knowntrans,
                                 sskm=chelt_db_connection.sskm,
                                 deubnk=chelt_db_connection.deubnk,
                                 n26=chelt_db_connection.n26,
                                 currentConto=conto,
                                 selectedStartDate=selectedStartDate,
                                 selectedEndDate=selectedEndDate,
                                 hideintercontotrans=True)
    planvsReal.find_planned_in_real_expenses_table(hideintercontotrans=True)
    planvsReal.find_unplanned_real_expenses(hideintercontotrans=True)
    # print(planvsReal.unplanned_real_expenses)
    # print('planvsReal.sum_of_unplanned_real_expenses', planvsReal.sum_of_unplanned_real_expenses)
    # print('planvsReal.sum_of_unplanned_real_expenses_without_n26',
    # planvsReal.sum_of_unplanned_real_expenses_without_n26)
    # print('planvsReal.sum_of_unplanned_real_expenses_only_n26', planvsReal.sum_of_unplanned_real_expenses_only_n26)
    # print('planvsReal.unplanned_real_expenses_no_category', planvsReal.unplanned_real_expenses_no_category)


def app_online(chelt_db_connection, id_users, conto, selectedStartDate, selectedEndDate):
    if selectedStartDate.month == selectedEndDate.month:
        month = convert_months(selectedStartDate.month)
    else:
        month = 'month'
    year = selectedStartDate.year
    app_online = CheltYearlyOnline(chelt_db=chelt_db_connection.chelt_db,
                                   yearly_all=chelt_db_connection.yearly_all,
                                   id_users=id_users)
    app_online.month = month
    app_online.year = year
    app_online.conto = conto
    print('conto, year, month', app_online.conto, app_online.year, app_online.month)
    app_online.prepareTablePlan()
    # print('app_online.tot_val_of_planned_expenses', app_online.tot_val_of_planned_expenses)
    print('app_online.planned_expenses_per_conto', app_online.planned_expenses_per_conto)
    # print('app_online.planned_expenses_per_conto_per_month', app_online.planned_expenses_per_conto_per_month)
    # print('app_online.planned_expenses_per_category', app_online.planned_expenses_per_category)
    # print('app_online.planned_expenses_per_category_per_month', app_online.planned_expenses_per_category_per_month)
    # print('app_online.planned_expenses_average', app_online.planned_expenses_average)
    #
    # print('app_online.tot_val_of_real_expenses', app_online.tot_val_of_real_expenses)
    # print('app_online.real_expenses_per_conto', app_online.real_expenses_per_conto)
    # print('app_online.real_expenses_per_conto_per_month', app_online.real_expenses_per_conto_per_month)
    # print('app_online.real_expenses_per_category', app_online.real_expenses_per_category)
    # print('app_online.real_expenses_per_category_per_month', app_online.real_expenses_per_category_per_month)
    # print('app_online.real_expenses_average', app_online.real_expenses_average)
    #
    # print('app_online.tot_val_of_real_income', app_online.tot_val_of_real_income)
    # print('app_online.real_income_per_conto', app_online.real_income_per_conto)
    # print('app_online.real_income_per_conto_per_month', app_online.real_income_per_conto_per_month)
    # print('app_online.real_income_per_category', app_online.real_income_per_category)
    # print('app_online.real_income_per_category_per_month', app_online.real_income_per_category_per_month)
    # print('app_online.real_income_average', app_online.real_income_average)
    #
    # print('app_online.tot_val_of_planned_income', app_online.tot_val_of_planned_income)
    # print('app_online.planned_income_per_conto', app_online.planned_income_per_conto)
    # print('app_online.planned_income_per_conto_per_month', app_online.planned_income_per_conto_per_month)
    # print('app_online.planned_income_per_category', app_online.planned_income_per_category)
    # print('app_online.planned_income_per_category_per_month', app_online.planned_income_per_category_per_month)
    # print('app_online.planned_income_average', app_online.planned_income_average)
    #
    # print('app_online.all_year_months', app_online.all_year_months)
    print()
    # print('app_online.get_yearly_values', app_online.get_yearly_values('planned_expenses'))
    # print('app_online.get_monthly_values_per_category', app_online.get_monthly_values_per_category('planned_expenses'))
    # print('app_online.get_monthly_values_per_category', app_online.get_monthly_values_per_category('real_expenses'))
    # print('app_online.real_expenses_per_category_per_month', app_online.real_expenses_per_category_per_month)

    # list_of_cat = []
    # # new_planned_expenses_per_category_per_month, new_real_expenses_per_category_per_month = app_online.get_common_categories(app_online.planned_expenses_per_category_per_month, app_online.real_expenses_per_category_per_month)
    # # print('len(new_planned_expenses_per_category_per_month)', new_planned_expenses_per_category_per_month)
    # # print('len(new_real_expenses_per_category_per_month)', new_real_expenses_per_category_per_month)
    # planned = app_online.planned_expenses_per_category_per_month.copy()
    # real = app_online.real_expenses_per_category_per_month.copy()
    # app_online.year = year - 1
    # app_online.prepareTablePlan()
    # # app_online.conto = conto
    # print('conto, year, month', app_online.conto, app_online.year, app_online.month)
    #
    # print('planned', len(planned), planned)
    # print('real', len(real), real)
    # print('app_online.real_expenses_per_conto_per_month', len(app_online.real_expenses_per_category_per_month), app_online.real_expenses_per_category_per_month)
    # list_of_new_dicts = app_online.get_common_categories_new(planned, real, app_online.real_expenses_per_category_per_month)
    # print(100*'Ö')
    # for ddd in list_of_new_dicts:
    #     print(len(ddd))
    # res = app_online.get_total_and_average_values_for_time(year_before=True)
    # for k, v in res.items():
    #     # print(k, type(v))
    #     if isinstance(v, dict):
    #         print(k)
    #         for key, value in v.items():
    #             print('\t', key, value)
    #     else:
    #         print(k, v)


def main():
    script_start_time = time.time()
    selectedStartDate = datetime(2025, 1, 1, 0, 0, 0).date()
    # selectedStartDate = datetime(2025, 6, 1, 0, 0, 0).date()
    selectedEndDate = datetime(2025, 12, 31, 0, 0, 0).date()

    chelt_db_connection = DB_Connection(rappmysql.ini_chelt)
    conto = 'all'
    id_users = 1
    print(selectedStartDate, selectedEndDate)
    # chelt_app(id_users, chelt_db_connection)
    # cheltuieli_planificate(chelt_db_connection, conto, selectedStartDate, selectedEndDate, id_users)
    # app_income(chelt_db_connection, conto, selectedStartDate, selectedEndDate)
    # app_reale(chelt_db_connection, conto, selectedStartDate, selectedEndDate, id_users)
    # app_planvsReal(chelt_db_connection, conto, selectedStartDate, selectedEndDate)
    app_online(chelt_db_connection, id_users, conto, selectedStartDate, selectedEndDate)

    scrip_end_time = time.time()
    duration = scrip_end_time - script_start_time
    duration = time.strftime("%H:%M:%S", time.gmtime(duration))
    print('run time: {}'.format(duration))


if __name__ == '__main__':
    # parser = argparse.ArgumentParser(description=textwrap.dedent('''Start a GUI for an installed package'''),
    #                                  formatter_class=argparse.RawTextHelpFormatter)
    #
    # # parser.add_argument('department', type=str, default='all', help=textwrap.dedent('''"TF"/"TL"'''))
    # # parser.add_argument('-s', '--schema', type=str, help=textwrap.dedent('''"Vxx"/"ya_svc_dslotan_sh"'''))
    # # parser.add_argument('-pn', '--partno', type=str, default='all',
    # #                     help=textwrap.dedent('''evaluate only one partnumber'''))
    # # parser.add_argument('-det', '--details', action="store_true",
    # #                     help=textwrap.dedent('''show evaluation process'''))
    # parser.add_argument('-p', '--package', type=str, default='all',
    #                     help=textwrap.dedent('''installed package'''))
    #
    # args = parser.parse_args()
    # if args.package != 'all':
    #     start_gui(args.package)
    main()
