Use python pyqt6 and design a fully fledged replacement tool for quickbooks focusing on creating, saving, managing and mailing invoices. here is some code to start with: import sys
import json
import os
from datetime import datetime
import smtplib
from email.mime.text import MIMEText
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
import pandas as pd
from PyQt6 import QtWidgets, QtGui

# Define file paths
CLIENTS_FILE = 'clients.json'
LINE_ITEMS_FILE = 'line_items.json'
INVOICES_DIR = 'invoices'

# Ensure invoices directory exists
os.makedirs(INVOICES_DIR, exist_ok=True)

# Function to load clients from JSON
def load_clients():
    if os.path.exists(CLIENTS_FILE):
        with open(CLIENTS_FILE, 'r') as f:
            return json.load(f)
    return {}

# Function to load line items from JSON
def load_line_items():
    if os.path.exists(LINE_ITEMS_FILE):
        with open(LINE_ITEMS_FILE, 'r') as f:
            return json.load(f)
    return {}

# Initialize clients and line items
clients = load_clients()
line_items_data = load_line_items()

# GUI Application
class InvoiceCreator(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.clients = load_clients()
        self.line_items_data = load_line_items()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("Invoice Creator")
        layout = QtWidgets.QVBoxLayout()

        # Client Management
        self.client_name_input = QtWidgets.QLineEdit(self)
        self.client_name_input.setPlaceholderText("Client Name")
        layout.addWidget(self.client_name_input)

        self.client_email_input = QtWidgets.QLineEdit(self)
        self.client_email_input.setPlaceholderText("Client Email")
        layout.addWidget(self.client_email_input)

        self.client_address_input = QtWidgets.QLineEdit(self)
        self.client_address_input.setPlaceholderText("Client Address")
        layout.addWidget(self.client_address_input)

        self.add_client_button = QtWidgets.QPushButton("Add Client")
        self.add_client_button.clicked.connect(self.add_client)
        layout.addWidget(self.add_client_button)

        # Drop-down list for clients
        self.client_combo = QtWidgets.QComboBox(self)
        self.client_combo.addItems(list(self.clients.keys()))
        layout.addWidget(self.client_combo)

        # Line Item Management
        self.line_item_name_input = QtWidgets.QLineEdit(self)
        self.line_item_name_input.setPlaceholderText("Line Item Name")
        layout.addWidget(self.line_item_name_input)

        self.line_item_price_input = QtWidgets.QLineEdit(self)
        self.line_item_price_input.setPlaceholderText("Line Item Price")
        layout.addWidget(self.line_item_price_input)

        self.add_line_item_button = QtWidgets.QPushButton("Add Line Item")
        self.add_line_item_button.clicked.connect(self.add_line_item)
        layout.addWidget(self.add_line_item_button)

        # Drop-down list for line items
        self.item_combo = QtWidgets.QComboBox(self)
        self.item_combo.addItems(list(self.line_items_data.keys()))
        layout.addWidget(self.item_combo)

        # Quantity, Discounts, and Taxes
        self.quantity_input = QtWidgets.QLineEdit(self)
        self.quantity_input.setPlaceholderText("Quantity")
        layout.addWidget(self.quantity_input)

        self.discount_input = QtWidgets.QLineEdit(self)
        self.discount_input.setPlaceholderText("Discount (%)")
        layout.addWidget(self.discount_input)

        self.tax_rate_input = QtWidgets.QLineEdit(self)
        self.tax_rate_input.setPlaceholderText("Tax Rate (%)")
        layout.addWidget(self.tax_rate_input)

        # Output Format Selection
        self.output_format_combo = QtWidgets.QComboBox(self)
        self.output_format_combo.addItems(["PDF", "Excel"])
        layout.addWidget(self.output_format_combo)

        # Button to create invoice
        self.create_invoice_button = QtWidgets.QPushButton("Create Invoice")
        self.create_invoice_button.clicked.connect(self.create_invoice)
        layout.addWidget(self.create_invoice_button)

        # Button to view invoices
        self.view_invoices_button = QtWidgets.QPushButton("View Invoices")
        self.view_invoices_button.clicked.connect(self.view_invoices)
        layout.addWidget(self.view_invoices_button)

        # Log Message Area
        self.log_area = QtWidgets.QTextEdit(self)
        self.log_area.setReadOnly(True)
        layout.addWidget(self.log_area)

        self.setLayout(layout)

    def log_message(self, message):
        """Logs message to the text area."""
        self.log_area.append(message)

    def add_client(self):
        """Add a new client to the system."""
        name = self.client_name_input.text()
        email = self.client_email_input.text()
        address = self.client_address_input.text()

        if not name or not email or not address:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("Please fill in all fields.")
            messagebox.exec()
            return
        
        if name in self.clients:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("Client already exists.")
            messagebox.exec()
            return
        
        self.clients[name] = {
            "email": email,
            "address": address
        }
        save_clients(self.clients)
        self.client_combo.clear()
        self.client_combo.addItems(list(self.clients.keys()))
        self.client_combo.setCurrentIndex(0)
        self.log_message(f"Client '{name}' added.")
        self.client_name_input.clear()
        self.client_email_input.clear()
        self.client_address_input.clear()

    def add_line_item(self):
        """Add a new line item."""
        item_name = self.line_item_name_input.text()
        price = self.line_item_price_input.text()

        if not item_name or not price or not price.replace('.', '').isdigit():
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("Please enter a valid item name and price.")
            messagebox.exec()
            return

        self.line_items_data[item_name] = {
            "price": float(price)
        }
        save_line_items(self.line_items_data)
        self.item_combo.clear()
        self.item_combo.addItems(list(self.line_items_data.keys()))
        self.item_combo.setCurrentIndex(0)
        self.log_message(f"Line item '{item_name}' added.")
        self.line_item_name_input.clear()
        self.line_item_price_input.clear()

    def create_invoice(self):
        """Generate the invoice based on provided inputs."""
        client_name = self.client_combo.currentText()
        vat_number = entry_vat.get()  # Placeholders if additional inputs added.
        selected_item = self.item_combo.currentText()
        quantity = self.quantity_input.text()
        discount = self.discount_input.text()
        tax_rate = self.tax_rate_input.text()
        
        # Validate inputs
        if not client_name or not selected_item or not quantity.isdigit() or int(quantity) <= 0:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("Please fill in all fields correctly.")
            messagebox.exec()
            return
        
        quantity = int(quantity)
        price = self.line_items_data[selected_item]['price']
        total = price * quantity
        
        # Apply discount
        if discount:
            discount = float(discount)
            total -= (total * (discount / 100))
        
        # Apply tax
        if tax_rate:
            tax_rate = float(tax_rate)
            total += (total * (tax_rate / 100))

        invoice_date = datetime.now().strftime("%Y-%m-%d")

        # Create DataFrame for invoice
        df = pd.DataFrame({
            "Item": [selected_item],
            "Quantity": [quantity],
            "Price": [price],
            "Total": [total]
        })

        # Save the invoice in the specified format
        output_format = self.output_format_combo.currentText()
        invoice_filename = f"{client_name}_invoice_{invoice_date}"

        if output_format == "PDF":
            self.create_pdf(client_name, vat_number, invoice_date, df, invoice_filename)
        elif output_format == "Excel":
            self.create_excel(client_name, vat_number, invoice_date, df, invoice_filename)
        else:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("Please select a valid output format.")
            messagebox.exec()

    # PDF generation function
    def create_pdf(self, client, vat, invoice_date, df, invoice_filename):
        """Generate PDF invoice."""
        pdf_filename = os.path.join(INVOICES_DIR, f"{invoice_filename}.pdf")
        c = canvas.Canvas(pdf_filename, pagesize=letter)
        c.drawString(100, 750, f"Invoice Date: {invoice_date}")
        c.drawString(100, 730, f"VAT Number: {vat}")
        c.drawString(100, 710, f"Client: {client}")

        c.drawString(100, 680, "Item Details:")
        y_position = 660
        for index, row in df.iterrows():
            c.drawString(100, y_position, f"{row['Item']} - Qty: {row['Quantity']} - Price: {row['Price']} - Total: {row['Total']:.2f}")
            y_position -= 20

        c.save()
        self.log_message(f"Invoice saved as {pdf_filename}")
        self.send_email_invoice(client, invoice_filename)

    # Excel generation function
    def create_excel(self, client, vat, invoice_date, df, invoice_filename):
        """Generate Excel invoice."""
        excel_filename = os.path.join(INVOICES_DIR, f"{invoice_filename}.xlsx")
        df.to_excel(excel_filename, index=False, sheet_name='Invoice')
        
        # Add VAT and date in a header
        with pd.ExcelWriter(excel_filename, engine='openpyxl', mode='a') as writer:
            workbook = writer.book
            worksheet = workbook.active
            worksheet.insert_rows(1)
            worksheet['A1'] = "Invoice Date:"
            worksheet['B1'] = invoice_date
            worksheet.append(["VAT Number:", vat])

        self.log_message(f"Invoice saved as {excel_filename}")
        self.send_email_invoice(client, invoice_filename)

    # Function to send the invoice via email
    def send_email_invoice(self, client, invoice_filename):
        """Send the invoice via email."""
        email = self.clients[client]['email']
        subject = f"Invoice: {invoice_filename}"
        body = f"Dear {client},\n\nPlease find attached your invoice: {invoice_filename}.\n\nThanks!"

        # Note: For demonstration purposes, SMTP settings are hardcoded
        smtp_server = 'smtp.office365.com'
        port = 587
        sender_email = 'your_email@hotmail.com'
        sender_password = 'your_password'
        
        msg = MIMEText(body)
        msg['Subject'] = subject
        msg['From'] = sender_email
        msg['To'] = email

        try:
            with smtplib.SMTP(smtp_server, port) as server:
                server.starttls()
                server.login(sender_email, sender_password)
                server.send_message(msg)
            self.log_message(f"Invoice sent to {client} at {email}.")
        except Exception as e:
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText(f"Failed to send email: {e}")
            messagebox.exec()

    def view_invoices(self):
        """Display the invoices directory contents."""
        if not os.path.exists(INVOICES_DIR):
            messagebox = QtWidgets.QMessageBox()
            messagebox.setText("No invoices available.")
            messagebox.exec()
            return

        invoices = os.listdir(INVOICES_DIR)
        invoices_string = "\n".join(invoices) if invoices else "No invoices found."
        messagebox = QtWidgets.QMessageBox()
        messagebox.setText(invoices_string)
        messagebox.exec()


# Run the application
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = InvoiceCreator()
    window.show()
    sys.exit(app.exec())