Primer commit
This commit is contained in:
134
fact.py
Normal file
134
fact.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog, messagebox
|
||||
from PIL import Image
|
||||
import pytesseract
|
||||
import hashlib
|
||||
import sqlite3
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
||||
from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
import os
|
||||
import re
|
||||
import base64
|
||||
import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
# Configuracion de OCR
|
||||
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # Cambia si es necesario
|
||||
|
||||
# Crear clave RSA para firmar
|
||||
clave_privada = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
clave_publica = clave_privada.public_key()
|
||||
|
||||
# Crear base de datos
|
||||
conn = sqlite3.connect("facturas.db")
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS facturas (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
nombre_archivo TEXT,
|
||||
datos_extraidos TEXT,
|
||||
hash TEXT,
|
||||
firma BLOB,
|
||||
csv TEXT,
|
||||
fecha TEXT,
|
||||
nif_emisor TEXT,
|
||||
nif_receptor TEXT,
|
||||
total REAL
|
||||
)''')
|
||||
conn.commit()
|
||||
|
||||
# Funciones del programa
|
||||
def seleccionar_archivo():
|
||||
ruta = filedialog.askopenfilename(filetypes=[("PDF o Imagen", "*.png;*.jpg;*.jpeg;*.tiff;*.bmp")])
|
||||
if ruta:
|
||||
texto = extraer_texto(ruta)
|
||||
nif_emisor = extraer_nif(texto, emisor=True)
|
||||
nif_receptor = extraer_nif(texto, emisor=False)
|
||||
total = extraer_total(texto)
|
||||
fecha = extraer_fecha(texto)
|
||||
hash_valor = generar_hash(texto)
|
||||
firma = firmar_texto(texto)
|
||||
csv = generar_csv(hash_valor)
|
||||
guardar_en_db(ruta, texto, hash_valor, firma, csv, fecha, nif_emisor, nif_receptor, total)
|
||||
generar_facturae(ruta, nif_emisor, nif_receptor, fecha, total, csv)
|
||||
messagebox.showinfo("Éxito", "Factura procesada y guardada.")
|
||||
mostrar_resultado(texto, hash_valor, csv, fecha, nif_emisor, nif_receptor, total)
|
||||
|
||||
def extraer_texto(ruta):
|
||||
imagen = Image.open(ruta)
|
||||
texto = pytesseract.image_to_string(imagen, lang='spa')
|
||||
return texto
|
||||
|
||||
def extraer_nif(texto, emisor=True):
|
||||
nif_pattern = r'\b[A-Z]?[0-9]{7,8}[A-Z]?\b'
|
||||
nifs = re.findall(nif_pattern, texto)
|
||||
return nifs[0] if emisor and nifs else (nifs[1] if len(nifs) > 1 else "")
|
||||
|
||||
def extraer_total(texto):
|
||||
total_pattern = r'Total[:\s]*([0-9]+[.,][0-9]{2})'
|
||||
match = re.search(total_pattern, texto, re.IGNORECASE)
|
||||
return float(match.group(1).replace(',', '.')) if match else 0.0
|
||||
|
||||
def extraer_fecha(texto):
|
||||
fecha_pattern = r'(\d{2}[\/\-]\d{2}[\/\-]\d{4})'
|
||||
match = re.search(fecha_pattern, texto)
|
||||
return match.group(1) if match else datetime.date.today().strftime("%d/%m/%Y")
|
||||
|
||||
def generar_hash(texto):
|
||||
return hashlib.sha256(texto.encode('utf-8')).hexdigest()
|
||||
|
||||
def firmar_texto(texto):
|
||||
firma = clave_privada.sign(
|
||||
texto.encode('utf-8'),
|
||||
padding.PKCS1v15(),
|
||||
hashes.SHA256()
|
||||
)
|
||||
return firma
|
||||
|
||||
def generar_csv(hash_valor):
|
||||
return "CSV-" + hash_valor[:10]
|
||||
|
||||
def guardar_en_db(nombre_archivo, texto, hash_valor, firma, csv, fecha, nif_emisor, nif_receptor, total):
|
||||
c.execute("""INSERT INTO facturas
|
||||
(nombre_archivo, datos_extraidos, hash, firma, csv, fecha, nif_emisor, nif_receptor, total)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(nombre_archivo, texto, hash_valor, firma, csv, fecha, nif_emisor, nif_receptor, total))
|
||||
conn.commit()
|
||||
|
||||
def generar_facturae(nombre_archivo, emisor, receptor, fecha, total, csv):
|
||||
root = ET.Element("Facturae")
|
||||
ET.SubElement(root, "Emisor").text = emisor
|
||||
ET.SubElement(root, "Receptor").text = receptor
|
||||
ET.SubElement(root, "Fecha").text = fecha
|
||||
ET.SubElement(root, "Total").text = str(total)
|
||||
ET.SubElement(root, "CSV").text = csv
|
||||
|
||||
tree = ET.ElementTree(root)
|
||||
nombre_xml = os.path.splitext(os.path.basename(nombre_archivo))[0] + "_facturae.xml"
|
||||
tree.write(nombre_xml)
|
||||
|
||||
def mostrar_resultado(texto, hash_valor, csv, fecha, nif_emisor, nif_receptor, total):
|
||||
resultado.delete("1.0", tk.END)
|
||||
resultado.insert(tk.END, f"📄 Texto extraído:\n{texto}\n")
|
||||
resultado.insert(tk.END, f"\n🔐 Hash: {hash_valor}\n")
|
||||
resultado.insert(tk.END, f"🧾 CSV generado: {csv}\n")
|
||||
resultado.insert(tk.END, f"📅 Fecha: {fecha}\n")
|
||||
resultado.insert(tk.END, f"🏢 NIF Emisor: {nif_emisor}\n")
|
||||
resultado.insert(tk.END, f"👤 NIF Receptor: {nif_receptor}\n")
|
||||
resultado.insert(tk.END, f"💰 Total: {total} €\n")
|
||||
|
||||
# GUI
|
||||
ventana = tk.Tk()
|
||||
ventana.title("Digitalizador de Facturas AEAT - v2.0")
|
||||
ventana.geometry("800x600")
|
||||
|
||||
titulo = tk.Label(ventana, text="Digitalizador de Facturas (Cumplimiento AEAT)", font=("Arial", 16))
|
||||
titulo.pack(pady=10)
|
||||
|
||||
boton = tk.Button(ventana, text="📤 Seleccionar factura", command=seleccionar_archivo, bg="#4CAF50", fg="white", font=("Arial", 12))
|
||||
boton.pack(pady=20)
|
||||
|
||||
resultado = tk.Text(ventana, wrap="word", height=20)
|
||||
resultado.pack(padx=10, pady=10, fill="both", expand=True)
|
||||
|
||||
ventana.mainloop()
|
||||
BIN
facturas.db
Normal file
BIN
facturas.db
Normal file
Binary file not shown.
BIN
modelo-factura-es-moderno-rojo-750px.png
Normal file
BIN
modelo-factura-es-moderno-rojo-750px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user