Extend this script upgrade improve and revise then provide the full version: import sys
import sqlite3
from datetime import datetime
import smtplib
import ssl
from email.message import EmailMessage
from PyQt6 import QtWidgets, QtGui
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QDialog, QMessageBox, QPushButton,
    QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit, QComboBox,
    QTableWidget, QTableWidgetItem, QDateEdit, QDoubleSpinBox, QSpinBox
)
from PyQt6.QtCore import Qt, QDate

# Utility function to load configurations
def load_config(file_path):
    try:
        with open(file_path, 'r') as f:
            return [line.strip() for line in f.readlines()]
    except Exception as e:
        print(f"Error loading configuration: {e}")
        return None

# Database Class
class Database:
    """Handles database operations for accounts, transactions, invoices, and users."""

    def __init__(self, db_name='accounting_system.db'):
        self.conn = sqlite3.connect(db_name)
        self.cursor = self.conn.cursor()
        self.initialize_db()

    def initialize_db(self):
        """Initialize database with all necessary tables."""
        self.cursor.execute("PRAGMA foreign_keys = ON;")
        self.create_tables()
        self.conn.commit()

    def create_tables(self):
        """Create the required tables in the database."""
        # User table for authentication
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                username TEXT NOT NULL UNIQUE,
                password TEXT NOT NULL,
                role TEXT NOT NULL CHECK(role IN ('Admin', 'User'))
            )
        ''')

        # Accounts table
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS accounts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL UNIQUE,
                type TEXT NOT NULL CHECK(type IN ('Assets', 'Liabilities', 'Equity', 'Income', 'Expenses'))
            )
        ''')

        # Transactions table
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                date TEXT NOT NULL,
                description TEXT,
                debit_account_id INTEGER NOT NULL,
                credit_account_id INTEGER NOT NULL,
                amount REAL NOT NULL CHECK(amount > 0),
                FOREIGN KEY(debit_account_id) REFERENCES accounts(id),
                FOREIGN KEY(credit_account_id) REFERENCES accounts(id)
            )
        ''')

        # Invoices table
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS invoices (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                invoice_number TEXT NOT NULL UNIQUE,
                date TEXT NOT NULL,
                customer_name TEXT NOT NULL,
                customer_email TEXT NOT NULL,
                description TEXT,
                amount REAL NOT NULL CHECK(amount > 0),
                status TEXT NOT NULL CHECK(status IN ('Pending', 'Sent', 'Paid'))
            )
        ''')

        # Recurring transactions
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS recurring_transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                description TEXT NOT NULL,
                debit_account_id INTEGER NOT NULL,
                credit_account_id INTEGER NOT NULL,
                amount REAL NOT NULL CHECK(amount > 0),
                frequency TEXT NOT NULL,
                next_execution_date TEXT NOT NULL,
                FOREIGN KEY(debit_account_id) REFERENCES accounts(id),
                FOREIGN KEY(credit_account_id) REFERENCES accounts(id)
            )
        ''')

    def execute(self, query, params=()):
        """Execute SQL query with parameters."""
        self.cursor.execute(query, params)
        self.conn.commit()

    def fetchall(self):
        """Fetch all results from the last executed query."""
        return self.cursor.fetchall()

    def fetchone(self):
        """Fetch one result from the last executed query."""
        return self.cursor.fetchone()

    def close(self):
        """Close the database connection."""
        self.conn.close()

# Email Handling Class
class EmailSender:
    """Handles sending emails with optional attachments."""

    def __init__(self, smtp_server, port, sender_email, sender_password):
        """Initialize the EmailSender with SMTP configurations."""
        self.smtp_server = smtp_server
        self.port = port
        self.sender_email = sender_email
        self.sender_password = sender_password

    def send_email(self, receiver_email, subject, body, attachment=None):
        """Send an email with the provided details."""
        message = EmailMessage()
        message["From"] = self.sender_email
        message["To"] = receiver_email
        message["Subject"] = subject
        message.set_content(body)

        if attachment:
            self.add_attachment(message, attachment)

        return self.attempt_send(message)

    def add_attachment(self, message, attachment):
        """Add an attachment to the email message."""
        with open(attachment, 'rb') as f:
            file_data = f.read()
            file_name = f.name
        message.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=file_name)

    def attempt_send(self, message):
        """Attempt to send the email message."""
        context = ssl.create_default_context()
        try:
            with smtplib.SMTP_SSL(self.smtp_server, self.port, context=context) as server:
                server.login(self.sender_email, self.sender_password)
                server.send_message(message)
            return True, "Email sent successfully."
        except Exception as e:
            return False, str(e)

class LoginDialog(QDialog):
    """Dialog for user authentication."""

    def __init__(self, db, parent=None):
        super().__init__(parent)
        self.db = db
        self.setWindowTitle("Login")
        self.setFixedSize(300, 200)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for the login dialog."""
        layout = QVBoxLayout()

        self.username_input = self.create_line_edit(layout, "Username:")
        self.password_input = self.create_line_edit(layout, "Password:", is_password=True)

        buttons_layout = QHBoxLayout()
        self.create_button(buttons_layout, "Login", self.login)
        self.create_button(buttons_layout, "Cancel", self.reject)
        layout.addLayout(buttons_layout)

        self.setLayout(layout)

    def create_line_edit(self, layout, label, is_password=False):
        """Create a line edit and add it to the layout."""
        line_edit = QLineEdit()
        if is_password:
            line_edit.setEchoMode(QLineEdit.EchoMode.Password)
        layout.addLayout(self.create_labelled_layout(label, line_edit))
        return line_edit

    def create_labelled_layout(self, label, widget):
        """Create a layout with a label and a widget."""
        h_layout = QHBoxLayout()
        h_label = QLabel(label)
        h_layout.addWidget(h_label)
        h_layout.addWidget(widget)
        return h_layout

    def create_button(self, layout, label, action):
        """Create a button and add it to the layout."""
        button = QPushButton(label)
        button.clicked.connect(action)
        layout.addWidget(button)

    def login(self):
        """Validate user credentials and allow access to the main window."""
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()

        user = self.db.fetchone('SELECT role FROM users WHERE username = ? AND password = ?', (username, password))
        if user:
            QMessageBox.information(self, "Login Successful", f"Welcome, {username}!")
            self.accept()
        else:
            QMessageBox.warning(self, "Login Failed", "Invalid username or password.")

class AddAccountDialog(QDialog):
    """Dialog for adding a new account to the database."""
    
    def __init__(self, db, parent=None):
        super().__init__(parent)
        self.db = db
        self.setWindowTitle("Add New Account")
        self.setFixedSize(300, 200)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for adding an account."""
        layout = QVBoxLayout()

        self.name_input = self.create_line_edit(layout, "Account Name:")
        self.type_combo = self.create_combo_box(layout, "Account Type:", ['Assets', 'Liabilities', 'Equity', 'Income', 'Expenses'])

        buttons_layout = QHBoxLayout()
        self.create_button(buttons_layout, "Add", self.add_account)
        self.create_button(buttons_layout, "Cancel", self.reject)
        layout.addLayout(buttons_layout)

        self.setLayout(layout)

    def create_line_edit(self, layout, label):
        """Create a line edit and add it to the layout."""
        line_edit = QLineEdit()
        layout.addLayout(self.create_labelled_layout(label, line_edit))
        return line_edit

    def create_combo_box(self, layout, label, items):
        """Create a combo box and add it to the layout."""
        combo_box = QComboBox()
        combo_box.addItems(items)
        layout.addLayout(self.create_labelled_layout(label, combo_box))
        return combo_box

    def create_labelled_layout(self, label, widget):
        """Create a layout with a label and a widget."""
        h_layout = QHBoxLayout()
        h_label = QLabel(label)
        h_layout.addWidget(h_label)
        h_layout.addWidget(widget)
        return h_layout

    def create_button(self, layout, label, action):
        """Create a button and add it to the layout."""
        button = QPushButton(label)
        button.clicked.connect(action)
        layout.addWidget(button)

    def add_account(self):
        """Add the account to the database after validation."""
        name = self.name_input.text().strip()
        acc_type = self.type_combo.currentText()

        if not name:
            QMessageBox.warning(self, "Input Error", "Account name cannot be empty.")
            return

        try:
            self.db.execute('INSERT INTO accounts (name, type) VALUES (?, ?)', (name, acc_type))
            QMessageBox.information(self, "Success", f"Account '{name}' added successfully.")
            self.accept()
        except sqlite3.IntegrityError:
            QMessageBox.warning(self, "Error", f"Account '{name}' already exists.")


class AddTransactionDialog(QDialog):
    """Dialog for adding a new transaction to the database."""
    
    def __init__(self, db, parent=None):
        super().__init__(parent)
        self.db = db
        self.setWindowTitle("Add New Transaction")
        self.setFixedSize(400, 300)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for adding a transaction."""
        layout = QVBoxLayout()

        self.desc_input = self.create_line_edit(layout, "Description:")
        self.date_input = self.create_date_edit(layout, "Date:")
        
        self.debit_combo = self.create_account_combo(layout, "Debit Account:")
        self.credit_combo = self.create_account_combo(layout, "Credit Account:")

        self.amount_input = self.create_double_spin_box(layout, "Amount (ZAR):")

        buttons_layout = QHBoxLayout()
        self.create_button(buttons_layout, "Add", self.add_transaction)
        self.create_button(buttons_layout, "Cancel", self.reject)
        layout.addLayout(buttons_layout)

        self.setLayout(layout)

    def create_line_edit(self, layout, label):
        """Create a line edit and add it to the layout."""
        line_edit = QLineEdit()
        layout.addLayout(self.create_labelled_layout(label, line_edit))
        return line_edit

    def create_date_edit(self, layout, label):
        """Create a date edit and add it to the layout."""
        date_edit = QDateEdit()
        date_edit.setCalendarPopup(True)
        date_edit.setDate(QDate.currentDate())
        layout.addLayout(self.create_labelled_layout(label, date_edit))
        return date_edit

    def create_account_combo(self, layout, label):
        """Create a combo box for account selection and add it to the layout."""
        combo_box = QComboBox()
        accounts = self.db.fetchall('SELECT name FROM accounts')
        combo_box.addItems([acc[0] for acc in accounts])
        layout.addLayout(self.create_labelled_layout(label, combo_box))
        return combo_box

    def create_double_spin_box(self, layout, label):
        """Create a double spin box for monetary input and add it to the layout."""
        spin_box = QDoubleSpinBox()
        spin_box.setMaximum(1000000000)
        spin_box.setPrefix("ZAR ")
        spin_box.setDecimals(2)
        layout.addLayout(self.create_labelled_layout(label, spin_box))
        return spin_box

    def create_labelled_layout(self, label, widget):
        """Create a layout with a label and a widget."""
        h_layout = QHBoxLayout()
        h_label = QLabel(label)
        h_layout.addWidget(h_label)
        h_layout.addWidget(widget)
        return h_layout

    def create_button(self, layout, label, action):
        """Create a button and add it to the layout."""
        button = QPushButton(label)
        button.clicked.connect(action)
        layout.addWidget(button)

    def add_transaction(self):
        """Add the transaction to the database after validation."""
        description = self.desc_input.text().strip()
        date = self.date_input.date().toString("yyyy-MM-dd")
        debit_account, credit_account = self.debit_combo.currentText(), self.credit_combo.currentText()
        amount = self.amount_input.value()

        if debit_account == credit_account:
            QMessageBox.warning(self, "Input Error", "Debit and Credit accounts must be different.")
            return
        if amount <= 0:
            QMessageBox.warning(self, "Input Error", "Amount must be greater than zero.")
            return

        try:
            debit_id = self.get_account_id(debit_account)
            credit_id = self.get_account_id(credit_account)
            self.db.execute('INSERT INTO transactions (date, description, debit_account_id, credit_account_id, amount) VALUES (?, ?, ?, ?, ?)', (date, description, debit_id, credit_id, amount))
            QMessageBox.information(self, "Success", "Transaction recorded successfully.")
            self.accept()
        except sqlite3.Error as e:
            QMessageBox.warning(self, "Error", f"Failed to record transaction: {e}")

    def get_account_id(self, account_name):
        """Get the account ID based on account name."""
        return self.db.fetchone('SELECT id FROM accounts WHERE name = ?', (account_name,))[0]


class AddInvoiceDialog(QDialog):
    """Dialog for creating a new invoice."""
    
    def __init__(self, db, email_sender, parent=None):
        super().__init__(parent)
        self.db = db
        self.email_sender = email_sender
        self.setWindowTitle("Create New Invoice")
        self.setFixedSize(400, 400)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for creating an invoice."""
        layout = QVBoxLayout()

        self.inv_num_input = self.create_line_edit(layout, "Invoice Number:")
        self.cust_name_input = self.create_line_edit(layout, "Customer Name:")
        self.cust_email_input = self.create_line_edit(layout, "Customer Email:")
        self.date_input = self.create_date_edit(layout, "Date:")
        self.desc_input = QTextEdit()
        layout.addWidget(QLabel("Description:"))
        layout.addWidget(self.desc_input)
        self.amount_input = self.create_double_spin_box(layout, "Amount (ZAR):")

        buttons_layout = QHBoxLayout()
        self.create_button(buttons_layout, "Create Invoice", self.create_invoice)
        self.create_button(buttons_layout, "Cancel", self.reject)
        layout.addLayout(buttons_layout)

        self.setLayout(layout)

    def create_line_edit(self, layout, label):
        """Create a line edit and add it to the layout."""
        line_edit = QLineEdit()
        layout.addLayout(self.create_labelled_layout(label, line_edit))
        return line_edit

    def create_date_edit(self, layout, label):
        """Create a date edit and add it to the layout."""
        date_edit = QDateEdit()
        date_edit.setCalendarPopup(True)
        date_edit.setDate(QDate.currentDate())
        layout.addLayout(self.create_labelled_layout(label, date_edit))
        return date_edit

    def create_double_spin_box(self, layout, label):
        """Create a double spin box for monetary input and add it to the layout."""
        spin_box = QDoubleSpinBox()
        spin_box.setMaximum(1000000000)
        spin_box.setPrefix("ZAR ")
        spin_box.setDecimals(2)
        layout.addLayout(self.create_labelled_layout(label, spin_box))
        return spin_box

    def create_labelled_layout(self, label, widget):
        """Create a layout with a label and a widget."""
        h_layout = QHBoxLayout()
        h_label = QLabel(label)
        h_layout.addWidget(h_label)
        h_layout.addWidget(widget)
        return h_layout

    def create_button(self, layout, label, action):
        """Create a button and add it to the layout."""
        button = QPushButton(label)
        button.clicked.connect(action)
        layout.addWidget(button)

    def create_invoice(self):
        """Create the invoice in the database and show success message."""
        invoice_number = self.inv_num_input.text().strip()
        customer_name = self.cust_name_input.text().strip()
        customer_email = self.cust_email_input.text().strip()
        date = self.date_input.date().toString("yyyy-MM-dd")
        description = self.desc_input.toPlainText().strip()
        amount = self.amount_input.value()

        if not all([invoice_number, customer_name, customer_email, description]):
            QMessageBox.warning(self, "Input Error", "All fields except amount are required.")
            return

        if amount <= 0:
            QMessageBox.warning(self, "Input Error", "Amount must be greater than zero.")
            return

        try:
            self.db.execute(
                'INSERT INTO invoices (invoice_number, date, customer_name, customer_email, description, amount, status) VALUES (?, ?, ?, ?, ?, ?, ?)',
                (invoice_number, date, customer_name, customer_email, description, amount, 'Pending')
            )
            QMessageBox.information(self, "Success", "Invoice created successfully.")
            self.accept()
        except sqlite3.IntegrityError:
            QMessageBox.warning(self, "Error", f"Invoice Number '{invoice_number}' already exists.")
        except sqlite3.Error as e:
            QMessageBox.warning(self, "Error", f"Failed to create invoice: {e}")


class SendInvoiceDialog(QDialog):
    """Dialog for sending an invoice via email."""
    
    def __init__(self, db, email_sender, parent=None):
        super().__init__(parent)
        self.db = db
        self.email_sender = email_sender
        self.setWindowTitle("Send Invoice")
        self.setFixedSize(400, 300)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for sending an invoice."""
        layout = QVBoxLayout()

        self.inv_combo = QComboBox()
        invoices = self.db.fetchall("SELECT invoice_number, customer_email FROM invoices WHERE status = 'Pending'")
        self.invoices = {f"{inv[0]} - {inv[1]}": inv[0] for inv in invoices}
        self.inv_combo.addItems(self.invoices.keys())
        layout.addLayout(self.create_labelled_layout("Select Invoice:", self.inv_combo))

        self.subject_input = self.create_line_edit(layout, "Email Subject:", "Your Invoice from Our Company")
        self.body_input = QTextEdit()
        layout.addWidget(QLabel("Email Body:"))
        layout.addWidget(self.body_input)

        buttons_layout = QHBoxLayout()
        self.create_button(buttons_layout, "Send", self.send_invoice)
        self.create_button(buttons_layout, "Cancel", self.reject)
        layout.addLayout(buttons_layout)

        self.setLayout(layout)

    def create_line_edit(self, layout, label, default_text=None):
        """Create a line edit and add it to the layout."""
        line_edit = QLineEdit(default_text) if default_text else QLineEdit()
        layout.addLayout(self.create_labelled_layout(label, line_edit))
        return line_edit

    def create_labelled_layout(self, label, widget):
        """Create a layout with a label and a widget."""
        h_layout = QHBoxLayout()
        h_label = QLabel(label)
        h_layout.addWidget(h_label)
        h_layout.addWidget(widget)
        return h_layout

    def create_button(self, layout, label, action):
        """Create a button and add it to the layout."""
        button = QPushButton(label)
        button.clicked.connect(action)
        layout.addWidget(button)

    def send_invoice(self):
        """Fetch invoice details and attempt to send the invoice via email."""
        invoice_display = self.inv_combo.currentText()
        invoice_number = self.invoices.get(invoice_display)
        subject = self.subject_input.text().strip()
        body = self.body_input.toPlainText().strip()

        if not invoice_number:
            QMessageBox.warning(self, "Error", "No invoice selected.")
            return

        invoice = self.db.fetchone('SELECT customer_email, description, amount FROM invoices WHERE invoice_number = ?', (invoice_number,))
        if not invoice:
            QMessageBox.warning(self, "Error", "Selected invoice not found.")
            return

        receiver_email = invoice[0]
        description = invoice[1]
        amount = invoice[2]
        invoice_content = self.generate_invoice_content(invoice_number, receiver_email, description, amount)

        invoice_filename = self.save_invoice_to_file(invoice_number, invoice_content)

        success, message = self.email_sender.send_email(receiver_email, subject, body, attachment=invoice_filename)
        if success:
            QMessageBox.information(self, "Success", "Invoice sent successfully.")
            # Update invoice status to 'Sent'
            self.db.execute('UPDATE invoices SET status = "Sent" WHERE invoice_number = ?', (invoice_number,))
            self.accept()
        else:
            QMessageBox.warning(self, "Error", f"Failed to send email: {message}")

    def generate_invoice_content(self, invoice_number, receiver_email, description, amount):
        """Generate the content for the invoice email."""
        return f"""
        Invoice Number: {invoice_number}
        Date: {datetime.now().strftime('%Y-%m-%d')}
        
        Customer Email: {receiver_email}

        Description:
        {description}

        Amount: ZAR {amount:.2f}

        Thank you for your business!
        """

    def save_invoice_to_file(self, invoice_number, content):
        """Save the invoice content to a file and return the filename."""
        invoice_filename = f"Invoice_{invoice_number}.txt"
        with open(invoice_filename, 'w') as f:
            f.write(content)
        return invoice_filename


class MainWindow(QMainWindow):
    """Main application window."""

    def __init__(self):
        super().__init__()
        self.db = Database()
        self.email_sender = None
        self.setWindowTitle("Simple Accounting System")
        self.setGeometry(100, 100, 800, 600)
        self.setup_ui()

    def setup_ui(self):
        """Set up the UI components for the main window."""
        menubar = self.menuBar()

        self.create_file_menu(menubar)
        self.create_manage_menu(menubar)
        self.create_invoices_menu(menubar)
        self.create_reports_menu(menubar)
        self.create_email_menu(menubar)

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout()
        self.info_label = QLabel("Welcome to the Simple Accounting System!")
        self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(self.info_label)
        self.central_widget.setLayout(self.layout)

    def create_file_menu(self, menubar):
        """Create the File menu in the menu bar."""
        file_menu = menubar.addMenu("File")
        exit_action = QtGui.QAction("Exit", self)
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

    def create_manage_menu(self, menubar):
        """Create the Manage menu in the menu bar."""
        manage_menu = menubar.addMenu("Manage")
        self.create_action(manage_menu, "Add Account", self.open_add_account_dialog)
        self.create_action(manage_menu, "Add Transaction", self.open_add_transaction_dialog)

    def create_invoices_menu(self, menubar):
        """Create the Invoices menu in the menu bar."""
        invoices_menu = menubar.addMenu("Invoices")
        self.create_action(invoices_menu, "Create Invoice", self.open_add_invoice_dialog)
        self.create_action(invoices_menu, "Send Invoice", self.open_send_invoice_dialog)

    def create_reports_menu(self, menubar):
        """Create the Reports menu in the menu bar."""
        reports_menu = menubar.addMenu("Reports")
        self.create_action(reports_menu, "Trial Balance", self.show_trial_balance)
        self.create_action(reports_menu, "Balance Sheet", self.show_balance_sheet)
        self.create_action(reports_menu, "Profit & Loss", self.show_profit_and_loss)

    def create_email_menu(self, menubar):
        """Create the Emails menu in the menu bar."""
        emails_menu = menubar.addMenu("Emails")
        self.create_action(emails_menu, "Setup Email", self.setup_email)

    def create_action(self, menu, label, slot):
        """Create an action in the menu."""
        action = QtGui.QAction(label, self)
        action.triggered.connect(slot)
        menu.addAction(action)

    def open_add_account_dialog(self):
        """Open the dialog to add a new account."""
        dialog = AddAccountDialog(self.db, self)
        dialog.exec()

    def open_add_transaction_dialog(self):
        """Open the dialog to add a new transaction."""
        dialog = AddTransactionDialog(self.db, self)
        dialog.exec()

    def open_add_invoice_dialog(self):
        """Open the dialog to create a new invoice."""
        dialog = AddInvoiceDialog(self.db, self.email_sender, self)
        dialog.exec()

    def open_send_invoice_dialog(self):
        """Open the dialog to send an invoice."""
        dialog = SendInvoiceDialog(self.db, self.email_sender, self)
        dialog.exec()

    def setup_email(self):
        """Open the dialog to set up email configuration."""
        dialog = EmailSetupDialog(self)
        if dialog.exec():
            self.email_sender = EmailSender(*dialog.get_email_config())
            QMessageBox.information(self, "Email Setup", "Email configuration saved successfully.")

    def show_trial_balance(self):
        """Show the dialog for trial balance report."""
        dialog = ReportDialog(self.db, report_type='Trial Balance', parent=self)
        dialog.exec()

    def show_balance_sheet(self):
        """Show the dialog for balance sheet report."""
        dialog = ReportDialog(self.db, report_type='Balance Sheet', parent=self)
        dialog.exec()

    def show_profit_and_loss(self):
        """Show the dialog for profit and loss report."""
        dialog = ReportDialog(self.db, report_type='Profit & Loss', parent=self)
        dialog.exec()

# Main application entry function
def main():
    """Main function to run the application."""
    app = QApplication(sys.argv)
    main_window = MainWindow()
    email_config = load_config('email_config.txt')

    if email_config:
        smtp_server, port, sender_email, sender_password = email_config
        main_window.email_sender = EmailSender(smtp_server, port, sender_email, sender_password)

    # Ensure user is logged in before proceeding
    login_dialog = LoginDialog(main_window.db, main_window)
    if login_dialog.exec():
        main_window.show()
        sys.exit(app.exec())
    else:
        sys.exit()  # Exit if login fails

if __name__ == "__main__":
    main()