Ir al contenido

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.

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.

AspectoLenguaje HeptoraPython en Heptora
ComplejidadProcesos simplesAutomatizaciones complejas
Control de flujoNo permitidoTotalmente permitido
LibreríasSolo funciones HeptoraTodo el ecosistema Python
Curva aprendizajeBajaMedia-Alta (requiere Python)
SeguridadMuy alta (restringido)Alta (más flexible)
Ideal paraUsuarios de negocioDesarrolladores

  • Python 3.8 o superior instalado en el robot local
  • La librería heptora se instala automáticamente con el robot
# Siempre al inicio de tu script
import heptora
# Importar módulos específicos si lo prefieres
from heptora import log, browser, excel, data

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(message: str) -> None

Descripció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 variables
total = len(facturas)
heptora.log.info(f"Total de facturas a procesar: {total}")

heptora.log.result(messageType: str, message: str) -> None

Descripció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:

# Éxito
heptora.log.result("ok", "Se han procesado 50 facturas con éxito.")
# Error controlado
heptora.log.result("ko", f"La factura {numero} no cumple las validaciones.")
# Error inesperado
heptora.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(message: str) -> None

Descripció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 datos
if not numero_factura:
heptora.log.force_ko("El número de la factura no puede estar vacío")
# Verificación de reglas de negocio
if estado == "Pagada":
heptora.log.force_ko("La factura ya está pagada, no requiere procesamiento")
# Validación de formato
if 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(file_path: str) -> None

Descripció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 generado
heptora.report.add_attachment("reportes/informe_ventas.pdf")
# Con rutas absolutas
import os
ruta_completa = os.path.join(os.getcwd(), "output", "resultado.xlsx")
heptora.report.add_attachment(ruta_completa)
# Verificar existencia antes de adjuntar
if os.path.exists("reporte_errores.csv"):
heptora.report.add_attachment("reporte_errores.csv")
heptora.log.info("Reporte de errores adjuntado")

Funciones para automatización web con Playwright.

heptora.browser.connect() -> Page

Descripció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 navegador
page = heptora.browser.connect()
# Navegar a una URL
page.goto("https://www.google.com")
# Interactuar con elementos
page.locator("#APjFqb").fill("Automatización con Heptora")
page.locator("input[name='btnK']").first.click()
# Esperar y obtener texto
page.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 formulario
page.wait_for_selector("#username")
# Introducir credenciales
username = 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 exitoso
try:
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 tabla
page.wait_for_selector("table.datos")
# Extraer datos de la tabla
filas = 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(url: str) -> None

Descripció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 simple
heptora.browser.go_to("https://portal.heptora.com")
# En un bucle
urls_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() -> None

Descripció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á presente
try:
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(
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 Excel
  • sheet_name (str): Nombre de la hoja
  • columns (List[str]): Lista de nombres de columnas a extraer
  • has_header (bool): Si la primera fila contiene encabezados

Retorna: Lista de diccionarios, cada uno representando una fila

Ejemplo básico:

# Definir columnas a leer
columnas = ["ID_Producto", "Nombre", "Stock", "Precio"]
# Cargar datos
productos = heptora.excel.load(
file_path="inventario.xlsx",
sheet_name="Almacen",
columns=columnas,
has_header=True
)
# Procesar los datos
for producto in productos:
heptora.log.info(
f"Producto {producto['ID_Producto']}: "
f"{producto['Nombre']} - Stock: {producto['Stock']}"
)

Ejemplo con procesamiento:

# Cargar facturas
facturas = heptora.excel.load(
"facturas_pendientes.xlsx",
"Enero",
["NumeroFactura", "Cliente", "Importe", "Estado"],
True
)
# Filtrar solo las pendientes
facturas_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 posterior
heptora.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(
values: List[Dict],
file_path: str,
sheet_name: str
) -> None

Descripción: Escribe datos en un fichero Excel.

Parámetros:

  • values (List[Dict]): Lista de diccionarios con los datos
  • file_path (str): Ruta donde guardar el archivo
  • sheet_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 reporte
facturas = 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 reporte
from datetime import datetime
fecha = 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 archivos
ventas_enero = heptora.excel.load("ventas_enero.xlsx", "Ventas", ["Producto", "Cantidad"], True)
ventas_febrero = heptora.excel.load("ventas_febrero.xlsx", "Ventas", ["Producto", "Cantidad"], True)
# Consolidar datos
todas_ventas = ventas_enero + ventas_febrero
# Agrupar por producto
from collections import defaultdict
ventas_por_producto = defaultdict(int)
for venta in todas_ventas:
producto = venta["Producto"]
cantidad = int(venta["Cantidad"])
ventas_por_producto[producto] += cantidad
# Preparar para escribir
consolidado = [
{"Producto": producto, "Total_Vendido": total}
for producto, total in ventas_por_producto.items()
]
# Escribir consolidado
heptora.excel.write(consolidado, "ventas_consolidadas.xlsx", "Resumen")

Funciones para automatización de aplicaciones de escritorio.

heptora.windows.open_app(path: str) -> None

Descripción: Abre una aplicación de Windows.

Ejemplo:

# Aplicaciones comunes
heptora.windows.open_app("calc.exe")
heptora.windows.open_app("notepad.exe")
heptora.windows.open_app("excel.exe")
# Con ruta completa
heptora.windows.open_app("C:\\Program Files\\MiApp\\app.exe")
# Esperar a que se abra
heptora.time.pause(2)

heptora.windows.type(text: str) -> None

Descripción: Simula la escritura de texto.

Ejemplo:

heptora.windows.type("Confirmación de pedido número 12345.")
# Con variables
numero_pedido = "PED-2024-001"
heptora.windows.type(f"Pedido: {numero_pedido}")

heptora.windows.press(*keys: str) -> None

Descripción: Simula la pulsación de teclas.

Ejemplos:

# Tecla simple
heptora.windows.press("enter")
heptora.windows.press("escape")
# Combinaciones
heptora.windows.press("control", "s") # Ctrl+S
heptora.windows.press("alt", "f4") # Alt+F4
heptora.windows.press("control", "shift", "escape") # Ctrl+Shift+Esc

heptora.windows.click_by_vision(base64Image: str) -> None

Descripció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(message: str) -> None

Descripción: Muestra un cuadro de diálogo.

Ejemplo:

heptora.windows.alert("El proceso ha finalizado. Revisa los resultados.")

heptora.beta.windows.press_macro(
requiredKey1: str,
requiredKey2: str,
*optionalKeys: str
) -> None

Descripció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(seconds: float = None) -> None

Descripción: Pausa la ejecución durante un tiempo determinado.

Parámetros:

  • seconds (float, opcional): Segundos a pausar

Ejemplos:

# Pausa de 5 segundos
heptora.time.pause(5)
# Pausa fraccional
heptora.time.pause(1.5)
# Pausa predefinida del proceso
heptora.time.pause()

Funciones para pasar datos entre bloques.

heptora.data.set(var_name: str, value: Any) -> None

Descripción: Guarda una variable para uso posterior.

Parámetros:

  • var_name (str): Nombre de la variable
  • value (Any): Valor a guardar (cualquier tipo serializable)

Ejemplos:

# Guardar diferentes tipos de datos
heptora.data.set("nombre_cliente", "Ana García")
heptora.data.set("total_facturas", 42)
heptora.data.set("precio_promedio", 125.50)
# Guardar estructuras complejas
user_data = {
"id": 101,
"name": "Carlos",
"roles": ["admin", "user"]
}
heptora.data.set("currentUser", user_data)
# Guardar listas
productos_procesados = ["PROD001", "PROD002", "PROD003"]
heptora.data.set("productos_ok", productos_procesados)

heptora.data.get(var_name: str) -> Any

Descripció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 simples
nombre = heptora.data.get("nombre_cliente")
total = heptora.data.get("total_facturas")
# Recuperar y usar estructuras complejas
user = heptora.data.get("currentUser")
if user and user["id"] == 101:
heptora.log.info(f"Procesando al usuario: {user['name']}")
# Con valor por defecto
facturas = heptora.data.get("facturas") or []
for factura in facturas:
# Procesar...
pass

Utiliza las características del lenguaje para código más limpio y robusto.

Bucles y comprensiones:

# Cargar y filtrar datos
facturas = heptora.excel.load("facturas.xlsx", "Hoja1", ["Numero", "Importe", "Estado"], True)
# Filtrar usando list comprehension
pendientes = [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 for
for 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ón
facturas = 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...

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
# Usar
facturas = heptora.data.get("facturas")
for factura in facturas:
procesar_con_reintentos(factura)

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 script
def 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")
# Ejecutar
main()

Las f-strings de Python son la forma más limpia de crear mensajes.

# ✅ Recomendado: f-strings
nombre = "Carlos"
edad = 30
heptora.log.info(f"Procesando usuario: {nombre} (edad: {edad})")
# ✅ Con expresiones
facturas = [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() antiguo
heptora.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 Heptora
usuario = heptora.data.get("portal_usuario")
password = heptora.data.get("portal_password")
api_key = heptora.data.get("api_key")
# Verificar que existen
if not usuario or not password:
heptora.log.force_ko("Faltan credenciales. Configúralas en Secretos.")
# Usar de forma segura
page = heptora.browser.connect()
page.goto("https://portal.com/login")
page.locator("#username").fill(usuario)
page.locator("#password").fill(password)

Documenta tu código para facilitar el mantenimiento.

"""
Proceso: Facturación Automática
Descripción: Procesa facturas pendientes y las envía al portal FACe
Autor: Equipo RPA
Fecha: 2024-01-15
"""
import heptora
from 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 proceso
if __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 heptora
from datetime import datetime
from 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)}")
raise

Lenguaje Heptora (restrictivo, seguro):

// No se pueden usar if, for, foreach
List<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 Python
facturas = 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)")

Puedes usar cualquier librería de Python instalada en el robot.

# Manipulación de fechas
from 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 regulares
import 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)

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.