146 lines
4.4 KiB
Python
146 lines
4.4 KiB
Python
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()
|