ProyectoGrupal/VerifactuMidAPI/presentacion/demo/demo.py

208 lines
7.2 KiB
Python

"""
Demo VeriFactu — flujo desde el front
======================================
Simula lo que haría el front al pulsar "Registrar":
1. Login en el backend (dolibarr-bff) para obtener JWT
2. Consulta el token VeriFactu almacenado en el backend
3. Envía una factura en formato Dolibarr directamente a VerifactuMidAPI
Uso:
python demo.py
python demo.py --backend http://localhost:5269 --api http://localhost:6789
python demo.py --usuario admin --password 12345678
"""
import sys
import json
import argparse
import urllib.request
import urllib.error
# ── Configuración por defecto ──────────────────────────────────────────────────
BACKEND_URL = "http://localhost:5269"
API_URL = "http://localhost:6789"
USUARIO = "admin"
PASSWORD = "12345678"
# ── Factura de ejemplo ─────────────────────────────────────────────────────────
# Mismo formato que el front recibe del backend (formato Dolibarr).
# Los campos emisor.nif y emisor.nombre los rellena la API desde el certificado.
FACTURA = {
"format": "dolibarr",
"invoice": {
"number": "FAC-DEMO-001",
"date": "2026-05-29",
"notePublic": "Servicios de consultoría tecnológica",
"lines": [
{
"description": "Desarrollo integración VeriFactu",
"quantity": 1,
"unitPrice": 121.00,
"taxRate": 21
},
{
"description": "Soporte técnico mensual",
"quantity": 2,
"unitPrice": 60.50,
"taxRate": 21
}
]
},
"client": {
"name": "Empresa Cliente S.L.",
"vatNumber": "B12345678"
},
"emisor": {
"nif": "",
"nombre": ""
},
"sistema": {
"nombre": "BYolivia Suite",
"nif_proveedor": "B87654321",
"version": "1.0.0"
}
}
# ── Helpers ────────────────────────────────────────────────────────────────────
def _color(text, code):
return f"\033[{code}m{text}\033[0m"
def ok(msg): print(_color(f"{msg}", "32"))
def err(msg): print(_color(f"{msg}", "31"))
def info(msg): print(_color(f"{msg}", "36"))
def titulo(msg): print(_color(f"\n{''*60}\n {msg}\n{''*60}", "34"))
def hacer_request(method, url, headers=None, body=None):
data = json.dumps(body).encode() if body else None
req = urllib.request.Request(url, data=data, headers=headers or {}, method=method)
if data:
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req, timeout=10) as r:
return r.status, json.loads(r.read())
except urllib.error.HTTPError as e:
try:
body = json.loads(e.read())
except Exception:
body = {"error": e.reason}
return e.code, body
except Exception as e:
return None, str(e)
# ── Pasos ──────────────────────────────────────────────────────────────────────
def paso1_login(backend, usuario, password):
titulo("PASO 1 — Login en el backend (dolibarr-bff)")
url = f"{backend}/api/auth/login"
info(f"POST {url}")
info(f"Usuario: {usuario}")
status, data = hacer_request("POST", url, body={"username": usuario, "password": password})
if status is None:
err(f"Error de red: {data}")
return None
print(f"\n HTTP {status}")
print(" " + json.dumps(data, indent=4, ensure_ascii=False).replace("\n", "\n "))
token = data.get("token") or data.get("Token")
if status != 200 or not token:
err("Login fallido. Comprueba usuario, contraseña y que el backend esté arrancado.")
return None
ok("Login correcto. JWT obtenido.")
return token
def paso2_obtener_token_verifactu(backend, jwt):
titulo("PASO 2 — Consultar token VeriFactu al backend")
url = f"{backend}/api/verifactu/token"
info(f"GET {url}")
status, data = hacer_request("GET", url, headers={"Authorization": f"Bearer {jwt}"})
if status is None:
err(f"Error de red: {data}")
return None
print(f"\n HTTP {status}")
print(" " + json.dumps(data, indent=4, ensure_ascii=False).replace("\n", "\n "))
token = data.get("token") or data.get("Token")
if status != 200 or not token:
err("No se pudo obtener el token VeriFactu. ¿Está el certificado registrado?")
return None
ok("Token VeriFactu obtenido.")
return token
def paso3_mostrar_factura():
titulo("PASO 3 — Factura preparada (formato Dolibarr)")
info("Misma estructura que el front recibe del backend.")
print()
print(" " + json.dumps(FACTURA, indent=4, ensure_ascii=False).replace("\n", "\n "))
def paso4_enviar_factura(api_url, token):
titulo("PASO 4 — Enviar factura a VerifactuMidAPI")
url = f"{api_url}/api/v1/facturas"
info(f"POST {url}")
info(f"Token: {token[:40]}" if len(token) > 40 else f"Token: {token}")
status, data = hacer_request(
"POST", url,
headers={"Authorization": f"Bearer {token}"},
body=FACTURA
)
if status is None:
err(f"Error de red: {data}")
return
print(f"\n HTTP {status}")
if data.get("success"):
ok("Factura procesada correctamente por la API.")
if data.get("csv"):
ok(f"Hash de cadena: {data['csv']}")
else:
err(f"La API devolvió error: {data.get('error', 'desconocido')}")
# ── Main ───────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(description="Demo flujo VeriFactu")
parser.add_argument("--backend", default=BACKEND_URL, help="URL del backend dolibarr-bff")
parser.add_argument("--api", default=API_URL, help="URL de VerifactuMidAPI")
parser.add_argument("--usuario", default=USUARIO, help="Usuario del backend")
parser.add_argument("--password", default=PASSWORD, help="Contraseña del backend")
args = parser.parse_args()
print(_color("\n VeriFactu Demo — flujo front → API", "1;37"))
print(_color(" Simula lo que haría el front al pulsar 'Registrar'\n", "2;37"))
# Paso 1: login → JWT
jwt = paso1_login(args.backend, args.usuario, args.password)
if not jwt:
sys.exit(1)
# Paso 2: token VeriFactu del backend
token_verifactu = paso2_obtener_token_verifactu(args.backend, jwt)
if not token_verifactu:
sys.exit(1)
# Paso 3: mostrar la factura
paso3_mostrar_factura()
# Paso 4: enviar a la API
paso4_enviar_factura(args.api, token_verifactu)
print()
if __name__ == "__main__":
main()