Python en Heptora
Este manual describe cómo desarrollar automatizaciones de negocio utilizando Python en la plataforma Heptora. A diferencia del Lenguaje Heptora, aquí puedes usar toda la potencia de Python junto con las funciones específicas de la librería heptora.
Filosofía del Lenguaje
Sección titulada «Filosofía del Lenguaje»El enfoque de Python en Heptora es ofrecer flexibilidad y potencia. Puedes utilizar:
- ✅ Librerías nativas de Python
- ✅ Estructuras de control (
if,for,while) - ✅ Todo el ecosistema del lenguaje
- ✅ Manejo de excepciones (
try/except) - ✅ Programación orientada a objetos
- ✅ Cualquier paquete de PyPI
La librería heptora proporciona las funciones de alto nivel para interactuar con aplicaciones, navegadores y la propia plataforma.
Cuándo Usar Python vs Lenguaje Heptora
Sección titulada «Cuándo Usar Python vs Lenguaje Heptora»| Aspecto | Lenguaje Heptora | Python en Heptora |
|---|---|---|
| Complejidad | Procesos simples | Automatizaciones complejas |
| Control de flujo | No permitido | Totalmente permitido |
| Librerías | Solo funciones Heptora | Todo el ecosistema Python |
| Curva aprendizaje | Baja | Media-Alta (requiere Python) |
| Seguridad | Muy alta (restringido) | Alta (más flexible) |
| Ideal para | Usuarios de negocio | Desarrolladores |
Instalación y Configuración
Sección titulada «Instalación y Configuración»Requisitos
Sección titulada «Requisitos»- Python 3.8 o superior instalado en el robot local
- La librería
heptorase instala automáticamente con el robot
Importar la Librería
Sección titulada «Importar la Librería»# Siempre al inicio de tu scriptimport heptora
# Importar módulos específicos si lo prefieresfrom heptora import log, browser, excel, dataFunciones Disponibles
Sección titulada «Funciones Disponibles»A continuación se detalla la API completa de la librería heptora para Python.
Funciones para registrar información y resultados.
heptora.log.info()
Sección titulada «heptora.log.info()»heptora.log.info(message: str) -> NoneDescripción: Publica un log informativo en la plataforma.
Parámetros:
message(str): Mensaje informativo a registrar
Ejemplos:
heptora.log.info("Proceso de carga de datos iniciado.")heptora.log.info(f"Procesando cliente: {nombre_cliente}")
# Con variablestotal = len(facturas)heptora.log.info(f"Total de facturas a procesar: {total}")heptora.log.result()
Sección titulada «heptora.log.result()»heptora.log.result(messageType: str, message: str) -> NoneDescripción: Registra un resultado final del proceso.
Parámetros:
messageType(str): Tipo de resultado:"ok","ko"o"error"message(str): Descripción del resultado
Ejemplos:
# Éxitoheptora.log.result("ok", "Se han procesado 50 facturas con éxito.")
# Error controladoheptora.log.result("ko", f"La factura {numero} no cumple las validaciones.")
# Error inesperadoheptora.log.result("error", "No se pudo conectar al servidor de base de datos.")Uso con condicionales:
if validacion_exitosa: heptora.log.result("ok", f"Factura {numero} procesada correctamente")else: heptora.log.result("ko", f"Factura {numero}: {motivo_error}")heptora.log.force_ko()
Sección titulada «heptora.log.force_ko()»heptora.log.force_ko(message: str) -> NoneDescripción: Registra un KO controlado y detiene el procesamiento del registro actual.
Parámetros:
message(str): Descripción del error controlado
Ejemplos:
# Validación de datosif not numero_factura: heptora.log.force_ko("El número de la factura no puede estar vacío")
# Verificación de reglas de negocioif estado == "Pagada": heptora.log.force_ko("La factura ya está pagada, no requiere procesamiento")
# Validación de formatoif not validar_nif(nif_cliente): heptora.log.force_ko(f"El NIF {nif_cliente} tiene un formato incorrecto")Funciones para gestionar archivos adjuntos en los resultados.
heptora.report.add_attachment()
Sección titulada «heptora.report.add_attachment()»heptora.report.add_attachment(file_path: str) -> NoneDescripción: Adjunta un fichero a la tarea actual. Se enviará en el email de resumen.
Parámetros:
file_path(str): Ruta del archivo a adjuntar
Ejemplos:
# Adjuntar un reporte generadoheptora.report.add_attachment("reportes/informe_ventas.pdf")
# Con rutas absolutasimport osruta_completa = os.path.join(os.getcwd(), "output", "resultado.xlsx")heptora.report.add_attachment(ruta_completa)
# Verificar existencia antes de adjuntarif os.path.exists("reporte_errores.csv"): heptora.report.add_attachment("reporte_errores.csv") heptora.log.info("Reporte de errores adjuntado")Browser
Sección titulada «Browser»Funciones para automatización web con Playwright.
heptora.browser.connect()
Sección titulada «heptora.browser.connect()»heptora.browser.connect() -> PageDescripción: Se conecta a una sesión de navegador gestionada por Heptora y devuelve un objeto Page de Playwright.
Retorna: Objeto Page de Playwright para interactuar con el navegador
Requisito previo: El navegador debe estar abierto previamente desde un bloque de código Heptora con heptora.browser.open().
Ejemplo básico:
# Conectar al navegadorpage = heptora.browser.connect()
# Navegar a una URLpage.goto("https://www.google.com")
# Interactuar con elementospage.locator("#APjFqb").fill("Automatización con Heptora")page.locator("input[name='btnK']").first.click()
# Esperar y obtener textopage.wait_for_selector(".g")resultados = page.locator(".g").all_text_contents()heptora.log.info(f"Se encontraron {len(resultados)} resultados")Ejemplo avanzado - Login:
page = heptora.browser.connect()page.goto("https://portal.empresa.com/login")
# Esperar que cargue el formulariopage.wait_for_selector("#username")
# Introducir credencialesusername = heptora.data.get("portal_username")password = heptora.data.get("portal_password")
page.locator("#username").fill(username)page.locator("#password").fill(password)page.locator("button[type='submit']").click()
# Verificar login exitosotry: page.wait_for_selector(".dashboard", timeout=5000) heptora.log.info("Login exitoso")except: heptora.log.force_ko("No se pudo iniciar sesión")Ejemplo - Scraping de datos:
page = heptora.browser.connect()page.goto("https://ejemplo.com/tabla-datos")
# Esperar tablapage.wait_for_selector("table.datos")
# Extraer datos de la tablafilas = page.locator("table.datos tbody tr").all()datos_extraidos = []
for fila in filas: columnas = fila.locator("td").all_text_contents() datos_extraidos.append({ "codigo": columnas[0], "nombre": columnas[1], "precio": columnas[2] })
heptora.log.info(f"Extraídos {len(datos_extraidos)} registros")heptora.data.set("datos_web", datos_extraidos)heptora.browser.go_to()
Sección titulada «heptora.browser.go_to()»heptora.browser.go_to(url: str) -> NoneDescripción: Forma simplificada de navegar a una URL, que incluye una pequeña pausa automática.
Parámetros:
url(str): URL completa a la que navegar
Ejemplo:
# Navegación simpleheptora.browser.go_to("https://portal.heptora.com")
# En un bucleurls_a_visitar = [ "https://ejemplo.com/pagina1", "https://ejemplo.com/pagina2", "https://ejemplo.com/pagina3"]
for url in urls_a_visitar: heptora.browser.go_to(url) # Procesar la página... heptora.log.info(f"Procesada: {url}")heptora.browser.solve_captcha()
Sección titulada «heptora.browser.solve_captcha()»heptora.browser.solve_captcha() -> NoneDescripción: Resuelve automáticamente el captcha en la página actual del navegador.
Ejemplo:
page = heptora.browser.connect()page.goto("https://sitio-con-captcha.com/login")
# Intentar resolver captcha si está presentetry: heptora.browser.solve_captcha() heptora.time.pause(3) # Esperar resolución heptora.log.info("Captcha resuelto")except Exception as e: heptora.log.info("No se encontró captcha o ya estaba resuelto")Funciones para trabajar con archivos Excel.
heptora.excel.load()
Sección titulada «heptora.excel.load()»heptora.excel.load( file_path: str, sheet_name: str, columns: List[str], has_header: bool) -> List[Dict]Descripción: Lee datos de un fichero Excel.
Parámetros:
file_path(str): Ruta del archivo Excelsheet_name(str): Nombre de la hojacolumns(List[str]): Lista de nombres de columnas a extraerhas_header(bool): Si la primera fila contiene encabezados
Retorna: Lista de diccionarios, cada uno representando una fila
Ejemplo básico:
# Definir columnas a leercolumnas = ["ID_Producto", "Nombre", "Stock", "Precio"]
# Cargar datosproductos = heptora.excel.load( file_path="inventario.xlsx", sheet_name="Almacen", columns=columnas, has_header=True)
# Procesar los datosfor producto in productos: heptora.log.info( f"Producto {producto['ID_Producto']}: " f"{producto['Nombre']} - Stock: {producto['Stock']}" )Ejemplo con procesamiento:
# Cargar facturasfacturas = heptora.excel.load( "facturas_pendientes.xlsx", "Enero", ["NumeroFactura", "Cliente", "Importe", "Estado"], True)
# Filtrar solo las pendientesfacturas_pendientes = [ f for f in facturas if f["Estado"] == "Pendiente"]
heptora.log.info( f"De {len(facturas)} facturas, " f"{len(facturas_pendientes)} están pendientes")
# Guardar para procesamiento posteriorheptora.data.set("facturas_a_procesar", facturas_pendientes)Ejemplo con validaciones:
clientes = heptora.excel.load("clientes.xlsx", "Hoja1", ["Nombre", "Email", "NIF"], True)
clientes_validos = []errores = []
for i, cliente in enumerate(clientes, start=2): # start=2 por header # Validar campos requeridos if not cliente.get("Email") or not cliente.get("NIF"): errores.append(f"Fila {i}: Faltan campos obligatorios") continue
# Validar formato de email if "@" not in cliente["Email"]: errores.append(f"Fila {i}: Email inválido") continue
clientes_validos.append(cliente)
heptora.log.info(f"Clientes válidos: {len(clientes_validos)}")heptora.log.info(f"Errores encontrados: {len(errores)}")
for error in errores: heptora.log.info(error)heptora.excel.write()
Sección titulada «heptora.excel.write()»heptora.excel.write( values: List[Dict], file_path: str, sheet_name: str) -> NoneDescripción: Escribe datos en un fichero Excel.
Parámetros:
values(List[Dict]): Lista de diccionarios con los datosfile_path(str): Ruta donde guardar el archivosheet_name(str): Nombre de la hoja
Ejemplo básico:
datos_nuevos = [ {"Nombre": "Juan", "Ciudad": "Madrid", "Edad": 30}, {"Nombre": "Laura", "Ciudad": "Barcelona", "Edad": 28}]
heptora.excel.write( datos_nuevos, "clientes_nuevos.xlsx", "Clientes")
heptora.log.info("Archivo Excel creado exitosamente")Ejemplo - Generar reporte de procesamiento:
# Procesar facturas y generar reportefacturas = heptora.data.get("facturas_a_procesar")resultados = []
for factura in facturas: try: # Procesar factura... resultado = procesar_factura(factura)
resultados.append({ "NumeroFactura": factura["NumeroFactura"], "Cliente": factura["Cliente"], "Estado": "Procesada", "Resultado": "OK", "Observaciones": "" }) except Exception as e: resultados.append({ "NumeroFactura": factura["NumeroFactura"], "Cliente": factura["Cliente"], "Estado": "Error", "Resultado": "KO", "Observaciones": str(e) })
# Guardar reportefrom datetime import datetimefecha = datetime.now().strftime("%Y%m%d_%H%M%S")archivo_reporte = f"reporte_facturas_{fecha}.xlsx"
heptora.excel.write(resultados, archivo_reporte, "Resultados")heptora.report.add_attachment(archivo_reporte)
heptora.log.info(f"Reporte generado: {archivo_reporte}")Ejemplo - Consolidar múltiples fuentes:
# Leer de múltiples archivosventas_enero = heptora.excel.load("ventas_enero.xlsx", "Ventas", ["Producto", "Cantidad"], True)ventas_febrero = heptora.excel.load("ventas_febrero.xlsx", "Ventas", ["Producto", "Cantidad"], True)
# Consolidar datostodas_ventas = ventas_enero + ventas_febrero
# Agrupar por productofrom collections import defaultdictventas_por_producto = defaultdict(int)
for venta in todas_ventas: producto = venta["Producto"] cantidad = int(venta["Cantidad"]) ventas_por_producto[producto] += cantidad
# Preparar para escribirconsolidado = [ {"Producto": producto, "Total_Vendido": total} for producto, total in ventas_por_producto.items()]
# Escribir consolidadoheptora.excel.write(consolidado, "ventas_consolidadas.xlsx", "Resumen")Windows
Sección titulada «Windows»Funciones para automatización de aplicaciones de escritorio.
heptora.windows.open_app()
Sección titulada «heptora.windows.open_app()»heptora.windows.open_app(path: str) -> NoneDescripción: Abre una aplicación de Windows.
Ejemplo:
# Aplicaciones comunesheptora.windows.open_app("calc.exe")heptora.windows.open_app("notepad.exe")heptora.windows.open_app("excel.exe")
# Con ruta completaheptora.windows.open_app("C:\\Program Files\\MiApp\\app.exe")
# Esperar a que se abraheptora.time.pause(2)heptora.windows.type()
Sección titulada «heptora.windows.type()»heptora.windows.type(text: str) -> NoneDescripción: Simula la escritura de texto.
Ejemplo:
heptora.windows.type("Confirmación de pedido número 12345.")
# Con variablesnumero_pedido = "PED-2024-001"heptora.windows.type(f"Pedido: {numero_pedido}")heptora.windows.press()
Sección titulada «heptora.windows.press()»heptora.windows.press(*keys: str) -> NoneDescripción: Simula la pulsación de teclas.
Ejemplos:
# Tecla simpleheptora.windows.press("enter")heptora.windows.press("escape")
# Combinacionesheptora.windows.press("control", "s") # Ctrl+Sheptora.windows.press("alt", "f4") # Alt+F4heptora.windows.press("control", "shift", "escape") # Ctrl+Shift+Escheptora.windows.click_by_vision()
Sección titulada «heptora.windows.click_by_vision()»heptora.windows.click_by_vision(base64Image: str) -> NoneDescripción: Busca una imagen en pantalla y hace clic.
Ejemplo:
imagen_boton = "data:image/png;base64,iVBORw0KG..."heptora.windows.click_by_vision(imagen_boton)heptora.time.pause(1)heptora.windows.alert()
Sección titulada «heptora.windows.alert()»heptora.windows.alert(message: str) -> NoneDescripción: Muestra un cuadro de diálogo.
Ejemplo:
heptora.windows.alert("El proceso ha finalizado. Revisa los resultados.")heptora.beta.windows.press_macro()
Sección titulada «heptora.beta.windows.press_macro()»heptora.beta.windows.press_macro( requiredKey1: str, requiredKey2: str, *optionalKeys: str) -> NoneDescripción: Simula atajos de teclado complejos.
Ejemplo:
# Win+R (Ejecutar)heptora.beta.windows.press_macro("win", "r")Funciones para control de temporización.
heptora.time.pause()
Sección titulada «heptora.time.pause()»heptora.time.pause(seconds: float = None) -> NoneDescripción: Pausa la ejecución durante un tiempo determinado.
Parámetros:
seconds(float, opcional): Segundos a pausar
Ejemplos:
# Pausa de 5 segundosheptora.time.pause(5)
# Pausa fraccionalheptora.time.pause(1.5)
# Pausa predefinida del procesoheptora.time.pause()Funciones para pasar datos entre bloques.
heptora.data.set()
Sección titulada «heptora.data.set()»heptora.data.set(var_name: str, value: Any) -> NoneDescripción: Guarda una variable para uso posterior.
Parámetros:
var_name(str): Nombre de la variablevalue(Any): Valor a guardar (cualquier tipo serializable)
Ejemplos:
# Guardar diferentes tipos de datosheptora.data.set("nombre_cliente", "Ana García")heptora.data.set("total_facturas", 42)heptora.data.set("precio_promedio", 125.50)
# Guardar estructuras complejasuser_data = { "id": 101, "name": "Carlos", "roles": ["admin", "user"]}heptora.data.set("currentUser", user_data)
# Guardar listasproductos_procesados = ["PROD001", "PROD002", "PROD003"]heptora.data.set("productos_ok", productos_procesados)heptora.data.get()
Sección titulada «heptora.data.get()»heptora.data.get(var_name: str) -> AnyDescripción: Recupera una variable guardada previamente.
Parámetros:
var_name(str): Nombre de la variable
Retorna: El valor guardado, o None si no existe
Ejemplos:
# Recuperar datos simplesnombre = heptora.data.get("nombre_cliente")total = heptora.data.get("total_facturas")
# Recuperar y usar estructuras complejasuser = heptora.data.get("currentUser")if user and user["id"] == 101: heptora.log.info(f"Procesando al usuario: {user['name']}")
# Con valor por defectofacturas = heptora.data.get("facturas") or []for factura in facturas: # Procesar... passBuenas Prácticas
Sección titulada «Buenas Prácticas»1. Aprovecha Python al Máximo
Sección titulada «1. Aprovecha Python al Máximo»Utiliza las características del lenguaje para código más limpio y robusto.
Bucles y comprensiones:
# Cargar y filtrar datosfacturas = heptora.excel.load("facturas.xlsx", "Hoja1", ["Numero", "Importe", "Estado"], True)
# Filtrar usando list comprehensionpendientes = [f for f in facturas if f["Estado"] == "Pendiente"]mayores_1000 = [f for f in pendientes if float(f["Importe"]) > 1000]
heptora.log.info(f"Facturas pendientes mayores a 1000€: {len(mayores_1000)}")
# Procesar con forfor factura in mayores_1000: numero = factura["Numero"] importe = factura["Importe"]
heptora.log.info(f"Procesando factura {numero} por {importe}€") # Procesamiento...Condicionales complejas:
def validar_factura(factura): """Valida una factura según reglas de negocio."""
# Validar campos requeridos if not factura.get("Numero"): return False, "Falta número de factura"
if not factura.get("Cliente"): return False, "Falta cliente"
# Validar importes try: importe = float(factura.get("Importe", 0)) if importe <= 0: return False, "Importe debe ser mayor a 0" except ValueError: return False, "Importe inválido"
# Validar estado estados_validos = ["Pendiente", "Pagada", "Cancelada"] if factura.get("Estado") not in estados_validos: return False, f"Estado inválido. Debe ser: {', '.join(estados_validos)}"
return True, "OK"
# Usar la funciónfacturas = heptora.data.get("facturas")for factura in facturas: es_valida, mensaje = validar_factura(factura)
if not es_valida: heptora.log.force_ko(f"Factura {factura['Numero']}: {mensaje}") continue
# Procesar factura válida...2. Manejo Robusto de Errores
Sección titulada «2. Manejo Robusto de Errores»Usa try/except para gestionar errores de forma controlada.
Patrón básico:
facturas = heptora.data.get("facturas")
for factura in facturas: numero = factura["Numero"]
try: # Intentar procesar heptora.log.info(f"Procesando factura {numero}")
# Código que puede fallar resultado = procesar_en_sistema(factura)
heptora.log.result("ok", f"Factura {numero} procesada correctamente")
except ValueError as e: # Error de datos (controlado) heptora.log.result("ko", f"Factura {numero}: Error en datos - {str(e)}")
except ConnectionError as e: # Error de conectividad (inesperado) heptora.log.result("error", f"Factura {numero}: Error de conexión - {str(e)}")
except Exception as e: # Cualquier otro error heptora.log.result("error", f"Factura {numero}: Error inesperado - {str(e)}")Patrón avanzado con reintentos:
def procesar_con_reintentos(factura, max_intentos=3): """Procesa una factura con reintentos en caso de error."""
for intento in range(1, max_intentos + 1): try: heptora.log.info(f"Intento {intento}/{max_intentos} para factura {factura['Numero']}")
# Procesar resultado = enviar_a_portal(factura)
heptora.log.result("ok", f"Factura {factura['Numero']} procesada") return True
except ConnectionError: if intento < max_intentos: heptora.log.info(f"Error de conexión. Reintentando en 5 segundos...") heptora.time.pause(5) else: heptora.log.result("error", f"Factura {factura['Numero']}: Error tras {max_intentos} intentos") return False
except Exception as e: # Error no recuperable heptora.log.result("error", f"Error no recuperable: {str(e)}") return False
return False
# Usarfacturas = heptora.data.get("facturas")for factura in facturas: procesar_con_reintentos(factura)3. Organiza tu Código con Funciones
Sección titulada «3. Organiza tu Código con Funciones»Para scripts largos, define funciones para separar la lógica.
def cargar_datos_excel(ruta_archivo): """Carga y valida datos del archivo Excel.""" heptora.log.info(f"Cargando datos de: {ruta_archivo}")
columnas = ["Numero", "Cliente", "Importe", "Estado"] datos = heptora.excel.load(ruta_archivo, "Facturas", columnas, True)
heptora.log.info(f"Cargadas {len(datos)} facturas") return datos
def validar_datos(facturas): """Valida que las facturas cumplan los requisitos.""" validas = [] invalidas = []
for factura in facturas: if factura.get("Estado") == "Pendiente" and float(factura.get("Importe", 0)) > 0: validas.append(factura) else: invalidas.append(factura)
heptora.log.info(f"Válidas: {len(validas)}, Inválidas: {len(invalidas)}") return validas, invalidas
def procesar_facturas(facturas): """Procesa las facturas en el sistema.""" exitosas = 0 fallidas = 0
for factura in facturas: try: # Lógica de procesamiento... exitosas += 1 heptora.log.result("ok", f"Factura {factura['Numero']}: OK") except Exception as e: fallidas += 1 heptora.log.result("error", f"Factura {factura['Numero']}: {str(e)}")
return exitosas, fallidas
def generar_reporte(exitosas, fallidas): """Genera un reporte de resultados.""" resumen = { "Total_Procesadas": exitosas, "Total_Fallidas": fallidas, "Tasa_Exito": f"{(exitosas / (exitosas + fallidas) * 100):.2f}%" }
heptora.excel.write([resumen], "reporte_resumen.xlsx", "Resumen") heptora.report.add_attachment("reporte_resumen.xlsx")
# Flujo principal del scriptdef main(): # 1. Cargar datos facturas = cargar_datos_excel("facturas_pendientes.xlsx")
# 2. Validar validas, invalidas = validar_datos(facturas)
# 3. Procesar exitosas, fallidas = procesar_facturas(validas)
# 4. Reportar generar_reporte(exitosas, fallidas)
heptora.log.info("Proceso completado")
# Ejecutarmain()4. Usa F-Strings para Logs Dinámicos
Sección titulada «4. Usa F-Strings para Logs Dinámicos»Las f-strings de Python son la forma más limpia de crear mensajes.
# ✅ Recomendado: f-stringsnombre = "Carlos"edad = 30heptora.log.info(f"Procesando usuario: {nombre} (edad: {edad})")
# ✅ Con expresionesfacturas = [1, 2, 3, 4, 5]heptora.log.info(f"Total de facturas: {len(facturas)}")heptora.log.info(f"Suma de importes: {sum(importes):.2f}€")
# ❌ Evitar: concatenación con +heptora.log.info("Procesando usuario: " + nombre + " (edad: " + str(edad) + ")")
# ❌ Evitar: format() antiguoheptora.log.info("Procesando usuario: {} (edad: {})".format(nombre, edad))5. Seguridad en el Manejo de Datos Sensibles
Sección titulada «5. Seguridad en el Manejo de Datos Sensibles»Nunca incluyas contraseñas o claves en el código.
❌ NO hacer:
# ¡NUNCA hagas esto!usuario = "admin@empresa.com"password = "MiPasswordSecreto123"api_key = "sk-1234567890abcdef"✅ Hacer:
# Usar el gestor de secretos de Heptorausuario = heptora.data.get("portal_usuario")password = heptora.data.get("portal_password")api_key = heptora.data.get("api_key")
# Verificar que existenif not usuario or not password: heptora.log.force_ko("Faltan credenciales. Configúralas en Secretos.")
# Usar de forma segurapage = heptora.browser.connect()page.goto("https://portal.com/login")page.locator("#username").fill(usuario)page.locator("#password").fill(password)6. Comentarios y Documentación
Sección titulada «6. Comentarios y Documentación»Documenta tu código para facilitar el mantenimiento.
"""Proceso: Facturación AutomáticaDescripción: Procesa facturas pendientes y las envía al portal FACeAutor: Equipo RPAFecha: 2024-01-15"""
import heptorafrom datetime import datetime
# ==============================================================================# CONFIGURACIÓN# ==============================================================================ARCHIVO_FACTURAS = "facturas_enero.xlsx"UMBRAL_IMPORTE = 1000.0 # Solo facturas mayores a 1000€
# ==============================================================================# FUNCIONES AUXILIARES# ==============================================================================
def cargar_configuracion(): """ Carga configuración y secretos necesarios.
Returns: dict: Configuración del proceso """ return { "usuario": heptora.data.get("face_usuario"), "password": heptora.data.get("face_password"), "url_portal": "https://face.gob.es" }
def procesar_factura(factura, config): """ Procesa una factura individual.
Args: factura (dict): Datos de la factura config (dict): Configuración del proceso
Returns: bool: True si se procesó correctamente
Raises: ValueError: Si la factura no es válida ConnectionError: Si hay error de conexión """ # Validar factura if not factura.get("Numero"): raise ValueError("Falta número de factura")
# Conectar y procesar page = heptora.browser.connect() page.goto(config["url_portal"])
# ... lógica de procesamiento ...
return True
# ==============================================================================# FLUJO PRINCIPAL# ==============================================================================
def main(): """Función principal del proceso.""" heptora.log.info("=== INICIO: Procesamiento de Facturas ===")
# 1. Cargar configuración config = cargar_configuracion()
# 2. Cargar facturas facturas = heptora.excel.load( ARCHIVO_FACTURAS, "Facturas", ["Numero", "Cliente", "Importe"], True )
# 3. Filtrar por importe facturas_filtradas = [ f for f in facturas if float(f["Importe"]) >= UMBRAL_IMPORTE ]
heptora.log.info(f"Facturas a procesar: {len(facturas_filtradas)}")
# 4. Procesar cada factura for factura in facturas_filtradas: try: procesar_factura(factura, config) heptora.log.result("ok", f"Factura {factura['Numero']}: OK") except Exception as e: heptora.log.result("error", f"Factura {factura['Numero']}: {str(e)}")
heptora.log.info("=== FIN: Proceso completado ===")
# Ejecutar procesoif __name__ == "__main__": main()Ejemplo Completo: Proceso Avanzado de Facturas
Sección titulada «Ejemplo Completo: Proceso Avanzado de Facturas»Este ejemplo muestra un proceso completo con todas las mejores prácticas.
"""Proceso Avanzado: Gestión de Facturas con Portal FACe"""
import heptorafrom datetime import datetimefrom typing import List, Dict, Tuple
# ==============================================================================# CONFIGURACIÓN# ==============================================================================
CONFIG = { "archivo_entrada": "facturas_pendientes.xlsx", "hoja_entrada": "Facturas", "columnas": ["NumeroFactura", "CIF", "Importe", "Fecha"], "url_portal": "https://face.gob.es", "timeout_pagina": 10000 # 10 segundos}
# ==============================================================================# FUNCIONES DE CARGA Y VALIDACIÓN# ==============================================================================
def cargar_facturas() -> List[Dict]: """Carga facturas desde Excel.""" heptora.log.info("Cargando facturas...")
facturas = heptora.excel.load( CONFIG["archivo_entrada"], CONFIG["hoja_entrada"], CONFIG["columnas"], has_header=True )
heptora.log.info(f"Cargadas {len(facturas)} facturas") return facturas
def validar_factura(factura: Dict) -> Tuple[bool, str]: """ Valida una factura.
Returns: Tuple[bool, str]: (es_valida, mensaje_error) """ # Validar número if not factura.get("NumeroFactura"): return False, "Falta número de factura"
# Validar CIF cif = factura.get("CIF", "") if len(cif) != 9: return False, f"CIF inválido: {cif}"
# Validar importe try: importe = float(factura.get("Importe", 0)) if importe <= 0: return False, "Importe debe ser mayor a 0" except (ValueError, TypeError): return False, "Importe inválido"
return True, ""
def filtrar_facturas_validas(facturas: List[Dict]) -> Tuple[List[Dict], List[Dict]]: """Separa facturas válidas de inválidas.""" validas = [] invalidas = []
for factura in facturas: es_valida, error = validar_factura(factura)
if es_valida: validas.append(factura) else: factura["_error"] = error invalidas.append(factura) heptora.log.info( f"Factura {factura.get('NumeroFactura', 'SIN_NUM')}: {error}" )
heptora.log.info(f"Válidas: {len(validas)}, Inválidas: {len(invalidas)}") return validas, invalidas
# ==============================================================================# FUNCIONES DE PROCESAMIENTO WEB# ==============================================================================
def login_portal(page, usuario: str, password: str) -> bool: """Realiza login en el portal.""" try: heptora.log.info("Iniciando sesión en portal...")
page.goto(CONFIG["url_portal"] + "/login") page.wait_for_selector("#username", timeout=CONFIG["timeout_pagina"])
page.locator("#username").fill(usuario) page.locator("#password").fill(password) page.locator("button[type='submit']").click()
# Verificar login exitoso page.wait_for_selector(".dashboard", timeout=CONFIG["timeout_pagina"])
heptora.log.info("Login exitoso") return True
except Exception as e: heptora.log.result("error", f"Error en login: {str(e)}") return False
def procesar_factura_en_portal(page, factura: Dict) -> bool: """Procesa una factura en el portal web.""" numero = factura["NumeroFactura"]
try: heptora.log.info(f"Procesando factura {numero}...")
# Navegar a formulario page.goto(CONFIG["url_portal"] + "/nueva-factura") page.wait_for_selector("#form-factura", timeout=CONFIG["timeout_pagina"])
# Rellenar formulario page.locator("#numero").fill(str(factura["NumeroFactura"])) page.locator("#cif").fill(str(factura["CIF"])) page.locator("#importe").fill(str(factura["Importe"])) page.locator("#fecha").fill(str(factura["Fecha"]))
# Enviar page.locator("button#enviar").click()
# Esperar confirmación page.wait_for_selector(".mensaje-exito", timeout=CONFIG["timeout_pagina"])
heptora.log.result("ok", f"Factura {numero} procesada correctamente") return True
except Exception as e: heptora.log.result("error", f"Factura {numero}: {str(e)}") return False
# ==============================================================================# FUNCIONES DE REPORTE# ==============================================================================
def generar_reporte_invalidas(invalidas: List[Dict]): """Genera reporte de facturas inválidas.""" if not invalidas: return
reporte = [ { "NumeroFactura": f.get("NumeroFactura", "SIN_NUM"), "CIF": f.get("CIF", ""), "Importe": f.get("Importe", ""), "Error": f.get("_error", "") } for f in invalidas ]
archivo = f"facturas_invalidas_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" heptora.excel.write(reporte, archivo, "Invalidas") heptora.report.add_attachment(archivo)
heptora.log.info(f"Reporte de inválidas generado: {archivo}")
def generar_reporte_resumen(total: int, exitosas: int, fallidas: int, invalidas: int): """Genera reporte resumen del proceso.""" tasa_exito = (exitosas / total * 100) if total > 0 else 0
resumen = [{ "Total_Facturas": total, "Procesadas_OK": exitosas, "Procesadas_Error": fallidas, "Invalidas": invalidas, "Tasa_Exito": f"{tasa_exito:.2f}%", "Fecha_Proceso": datetime.now().strftime("%Y-%m-%d %H:%M:%S") }]
archivo = f"resumen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" heptora.excel.write(resumen, archivo, "Resumen") heptora.report.add_attachment(archivo)
heptora.log.info(f"Resumen generado: {archivo}")
# ==============================================================================# FLUJO PRINCIPAL# ==============================================================================
def main(): """Función principal del proceso.""" heptora.log.info("=" * 60) heptora.log.info("INICIO: Proceso de Facturación FACe") heptora.log.info("=" * 60)
# 1. CARGAR DATOS facturas = cargar_facturas() total_facturas = len(facturas)
# 2. VALIDAR DATOS validas, invalidas = filtrar_facturas_validas(facturas)
if not validas: heptora.log.force_ko("No hay facturas válidas para procesar") return
# 3. CONECTAR AL PORTAL page = heptora.browser.connect()
# Obtener credenciales usuario = heptora.data.get("face_usuario") password = heptora.data.get("face_password")
if not usuario or not password: heptora.log.force_ko("Faltan credenciales. Configúralas en Secretos.") return
# Login if not login_portal(page, usuario, password): heptora.log.force_ko("No se pudo iniciar sesión en el portal") return
# 4. PROCESAR FACTURAS VÁLIDAS exitosas = 0 fallidas = 0
for i, factura in enumerate(validas, 1): heptora.log.info(f"Procesando {i}/{len(validas)}...")
if procesar_factura_en_portal(page, factura): exitosas += 1 else: fallidas += 1
# Pausa entre facturas if i < len(validas): heptora.time.pause(2)
# 5. GENERAR REPORTES generar_reporte_invalidas(invalidas) generar_reporte_resumen(total_facturas, exitosas, fallidas, len(invalidas))
# 6. LOG FINAL heptora.log.info("=" * 60) heptora.log.info(f"Total facturas: {total_facturas}") heptora.log.info(f" - Procesadas OK: {exitosas}") heptora.log.info(f" - Procesadas con error: {fallidas}") heptora.log.info(f" - Inválidas: {len(invalidas)}") heptora.log.info("=" * 60) heptora.log.info("FIN: Proceso completado")
# ==============================================================================# PUNTO DE ENTRADA# ==============================================================================
if __name__ == "__main__": try: main() except Exception as e: heptora.log.result("error", f"Error fatal en el proceso: {str(e)}") raiseComparación: Lenguaje Heptora vs Python
Sección titulada «Comparación: Lenguaje Heptora vs Python»Mismo Proceso en Ambos Lenguajes
Sección titulada «Mismo Proceso en Ambos Lenguajes»Lenguaje Heptora (restrictivo, seguro):
// No se pueden usar if, for, foreachList<Dictionary<string, object>> facturas = (List<Dictionary<string, object>>)heptora.data.get("facturas");
Dictionary<string, object> factura = facturas[0];string numero = (string)factura["NumeroFactura"];
heptora.log.info("Procesando: " + numero);heptora.log.result("ok", "Factura procesada");Python (flexible, poderoso):
# Puedes usar todo Pythonfacturas = heptora.data.get("facturas")
for factura in facturas: numero = factura["NumeroFactura"]
# Usar if/else if factura["Importe"] > 1000: try: # Lógica compleja con try/except procesar_factura(factura) heptora.log.result("ok", f"Factura {numero} procesada") except Exception as e: heptora.log.result("error", f"Error: {str(e)}") else: heptora.log.info(f"Factura {numero} omitida (importe bajo)")Librerías Externas
Sección titulada «Librerías Externas»Puedes usar cualquier librería de Python instalada en el robot.
# Manipulación de fechasfrom datetime import datetime, timedelta
fecha_actual = datetime.now()hace_30_dias = fecha_actual - timedelta(days=30)
heptora.log.info(f"Fecha actual: {fecha_actual.strftime('%Y-%m-%d')}")
# Expresiones regularesimport re
def validar_email(email): patron = r'^[\w\.-]+@[\w\.-]+\.\w+$' return re.match(patron, email) is not None
# Requests para APIs (si está instalado)import requests
response = requests.get("https://api.ejemplo.com/datos")if response.status_code == 200: datos = response.json() heptora.data.set("datos_api", datos)¿Necesitas más ayuda?
Sección titulada «¿Necesitas más ayuda?»Si esta guía no resolvió tu problema o encontraste algún error en la documentación:
- Soporte técnico: help@heptora.com
- Describe claramente el problema que encontraste
- Incluye capturas de pantalla si es posible
- Indica qué pasos de la documentación seguiste
Nuestro equipo de soporte te ayudará a resolver cualquier problema.
Recursos Relacionados
Sección titulada «Recursos Relacionados»- Lenguaje Heptora - Alternativa restrictiva y segura
- Resultados de Ejecución - Entiende OK, KO y ERROR
- Gestión de Secretos - Almacena credenciales
- Playwright Python - Documentación oficial de Playwright