from tkinter import * from tkinter import filedialog, messagebox from PIL import Image, ImageTk import pytesseract import re import os import json import datetime import hashlib import qrcode import sqlite3 # Configuración del path de Tesseract pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # Base de datos de solo lectura (una vez creada) DB_PATH = "facturas.db" def init_db(): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS facturas ( hash TEXT PRIMARY KEY, datos TEXT, qr_path TEXT, fecha TEXT)''') conn.commit() conn.close() def seleccionar_archivo(): ruta = filedialog.askopenfilename(filetypes=[("Imágenes", "*.png;*.jpg;*.jpeg")]) if ruta: mostrar_factura(ruta) texto = extraer_texto(ruta) datos = extraer_datos(texto) mostrar_datos(datos) hash_val, qr_path = guardar_en_db(datos) mostrar_hash_qr(hash_val, qr_path) guardar_datos_json(datos) def mostrar_factura(ruta): imagen = Image.open(ruta) imagen = imagen.resize((500, 700)) img_tk = ImageTk.PhotoImage(imagen) img_label.config(image=img_tk) img_label.image = img_tk def extraer_texto(ruta): imagen = Image.open(ruta) return pytesseract.image_to_string(imagen, lang='spa') def extraer_datos(texto): return { "NIF Emisor": extraer_nif_emisor(texto), "NIF Receptor": extraer_nif_receptor(texto), "Fecha": extraer_fecha(texto), "Total": extraer_total(texto), "Texto Completo": texto } def mostrar_datos(datos): for widget in datos_frame.winfo_children(): widget.destroy() for campo, valor in datos.items(): Label(datos_frame, text=f"{campo}:", font=("Arial", 10, "bold")).pack(anchor="w") Label(datos_frame, text=valor, font=("Arial", 10), wraplength=350, justify=LEFT).pack(anchor="w") Label(datos_frame, text="").pack() def mostrar_hash_qr(hash_val, qr_path): Label(datos_frame, text="Hash SHA-256:", font=("Arial", 10, "bold")).pack(anchor="w") Label(datos_frame, text=hash_val, font=("Arial", 8), wraplength=350, justify=LEFT, fg="blue").pack(anchor="w") qr_img = Image.open(qr_path) qr_img = qr_img.resize((150, 150)) qr_tk = ImageTk.PhotoImage(qr_img) qr_label = Label(datos_frame, image=qr_tk) qr_label.image = qr_tk qr_label.pack(anchor="w", pady=10) def guardar_datos_json(datos): fecha_actual = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") nombre_archivo = f"factura_{fecha_actual}.json" with open(nombre_archivo, "w", encoding="utf-8") as f: json.dump(datos, f, ensure_ascii=False, indent=4) def guardar_en_db(datos): datos_str = json.dumps(datos, ensure_ascii=False) hash_val = hashlib.sha256(datos_str.encode("utf-8")).hexdigest() qr = qrcode.make(hash_val) qr_path = f"qr_{hash_val[:8]}.png" qr.save(qr_path) conn = sqlite3.connect(DB_PATH) c = conn.cursor() try: c.execute("INSERT INTO facturas (hash, datos, qr_path, fecha) VALUES (?, ?, ?, ?)", (hash_val, datos_str, qr_path, datos.get("Fecha", ""))) conn.commit() except sqlite3.IntegrityError: messagebox.showinfo("Info", "La factura ya ha sido registrada (hash duplicado).") finally: conn.close() return hash_val, qr_path def extraer_nif_emisor(texto): match = re.search(r'\b[A-Z0-9]{8,9}\b', texto) return match.group() if match else "No encontrado" def extraer_nif_receptor(texto): match = re.findall(r'\b[A-Z0-9]{8,9}\b', texto) if len(match) > 1: return match[1] return "No encontrado" def extraer_fecha(texto): match = re.search(r'\d{2}/\d{2}/\d{4}', texto) return match.group() if match else "No encontrada" def extraer_total(texto): match = re.search(r'(\d+[.,]\d{2})\s*[€€]', texto) return match.group(1) + " €" if match else "No encontrado" # GUI principal init_db() root = Tk() root.title("Visor de Factura + OCR") root.geometry("900x720") main_frame = Frame(root) main_frame.pack(fill=BOTH, expand=True) img_label = Label(main_frame) img_label.pack(side=LEFT, padx=10, pady=10) datos_frame = Frame(main_frame) datos_frame.pack(side=RIGHT, fill=Y, padx=10, pady=10) btn = Button(root, text="Seleccionar Factura", command=seleccionar_archivo) btn.pack(pady=10) root.mainloop()