Files
don_confiao_backend/.opencode/skills/tryton-rpc-probe/SKILL.md
monomono 86a67834d1 #51 docs(opencode): skill tryton-rpc-probe y agente de proyecto
Documenta como hacer requests RPC de prueba contra Tryton con
sabatron-tryton-rpc-client:
- .opencode/skills/tryton-rpc-probe/SKILL.md: comando base con docker compose
  dev (--no-deps), credenciales desde .env, como revelar estados HTTP
  (401/403/429) que la libreria enmascara, convencion de agrupacion de campos
  con punto ('template.' -> 'categories.') y sondas de ejemplo
- .opencode/agents/tryton-rpc-probe.md: subagente que obliga a cargar el skill
- AGENTS.md: referencia al skill para todos los agents del proyecto
2026-10-12 16:20:05 -05:00

5.9 KiB

name: tryton-rpc-probe description: Use cuando se necesite hacer requests RPC de prueba contra Tryton (probes) con el paquete sabatron-tryton-rpc-client. Dispara ante tryton, sabatron, probe rpc, model.product.search/read, model.product.category.read, fields_get, credenciales Tryton staging o verificaciones empíricas de respuestas RPC. NO usar curl: solo el paquete de python.

Probes RPC a Tryton con sabatron-tryton-rpc-client

Guía para ejecutar requests RPC de prueba (probes) contra Tryton dentro de este proyecto, usando el paquete sabatron-tryton-rpc-client y el contenedor de desarrollo. Sirve para verificar campos, modelos, credenciales y respuestas antes de planear o implementar cambios de integración (TDD: confirmar empíricamente antes de asumir).

Reglas obligatorias

  • Nunca usar curl. Solo el paquete python sabatron-tryton-rpc-client (el RPC de Tryton enmascara/muestra estados HTTP distintos que confunden a curl).
  • No hardcodear credenciales: leer los valores TRYTON_HOST, TRYTON_DATABASE, TRYTON_USERNAME, TRYTON_PASSWORD de .env (raíz del proyecto) y pasarlos al contenedor con -e. No imprimir la contraseña (a lo sumo imprimir el nombre de la base de datos).
  • Respetar rate-limit: ante HTTP 429 esperar (p. ej. ~120s) antes de reintentar; no hacer ráfagas de logins fallidos.
  • Verificar primero el login/credenciales con una sonda mínima antes de asumir que falla por campos o datos.

Comando base (plantilla)

Todos los probes se ejecutan con docker compose dev sin levantar dependencias (--no-deps):

docker compose -f docker-compose.dev.yml run --rm --no-deps \
  -e TRYTON_HOST=<host de .env> \
  -e TRYTON_DATABASE=<db de .env> \
  -e TRYTON_USERNAME=<usuario de .env> \
  -e TRYTON_PASSWORD=<password de .env> \
  django python -c '
import os
from sabatron_tryton_rpc_client.client import Client
c = Client(hostname=os.environ["TRYTON_HOST"], database=os.environ["TRYTON_DATABASE"], username=os.environ["TRYTON_USERNAME"], password=os.environ["TRYTON_PASSWORD"])
c.connect()
print("CONNECTED OK", os.environ["TRYTON_DATABASE"])
ctx = {"company": 1}
print(c.call("model.product.product.search", [[["salable", "=", True]], 0, 5, [["rec_name", "ASC"], ["id", None]], ctx]))
'

Patrón de la librería:

from sabatron_tryton_rpc_client.client import Client
c = Client(hostname=..., database=..., username=..., password=...)
c.connect()                                    # login
resultado = c.call("modelo.metodo", (args..., contexto))   # contexto {"company": 1}

Ver estados HTTP reales (401/403/429 enmascarados)

La librería enmascara los errores HTTP del login como UnboundLocalError: cannot access local variable 'response'... (bug en jsonrpc.py:__request). Para ver el código real, monkeypatchear el transporte XML-RPC y capturar ProtocolError:

import xmlrpc.client
from sabatron_tryton_rpc_client import jsonrpc
orig = xmlrpc.client.Transport.request
def wrapped(self, host, handler, body, verbose=False):
    try:
        return orig(self, host, handler, body, verbose=verbose)
    except xmlrpc.client.ProtocolError as e:
        print("HTTP_STATUS", e.errcode, repr(e.errmsg))
        raise
jsonrpc.Transport.request = wrapped
# luego Client(...).connect() / ServerProxy(...)

Guía rápida de códigos vistos en el proyecto:

  • HTTP 200 + fault JSON (p. ej. FATAL: database "..." does not exist): la DB no existe o el endpoint responde con error de aplicacion.
  • HTTP 401: credenciales rechazadas (usuario/password) en esa base de datos.
  • HTTP 403: ruta/método denegado (p. ej. common.db.list).
  • HTTP 429: rate-limit, esperar antes de reintentar.

Convención de campos RPC de Tryton (agrupación con punto)

Los campos con punto (ej. template.categories.name) NO llegan como una clave plana: Tryton los agrupa bajo la clave del modelo padre con puntos.

En model.product.product.read, con los fields ["id", "name", "template.categories", "template.categories.name"], la respuesta llega así:

{
  "id": 488,
  "name": "Cloruro de magnesio",
  "template.": {
    "id": 1248,
    "categories": [6],
    "categories.": [{"id": 6, "name": "Alimentos Transformados Y Granos"}]
  }
}

Combinaciones verificadas en staging (Tryton 8):

fields solicitados claves resultantes
template.categories categories: [ids] (sin categories.)
template.categories.id categories.: [{"id": ...}]
template.categories.name categories.: [{"id", "name"}] (id viene incluido)
ambos .id + .name igual que solo .name

Conclusión operativa: pedir template.categories.name basta para traer ids y nombres; template.categories.id es redundante. No hay active en product.category (fields_get lo confirma) → activar/desactivar categorías es solo local.

Ejemplos de sondas útiles

Login + datos de productos con categorias anidadas:

ctx = {"company": 1}
pids = c.call("model.product.product.search", [[["salable", "=", True]], 0, 1000, [["rec_name", "ASC"], ["id", None]], ctx])
detalles = c.call("model.product.product.read", (pids, ["id", "name", "default_uom.id", "default_uom.rec_name", "list_price", "template.categories", "template.categories.name"], ctx))

Listar los campos reales de un modelo (evita asumir campos):

campos = c.call("model.product.category.fields_get", ([], ctx))
print(sorted(campos))

Listar bases de datos (suele estar bloqueado con 403):

from sabatron_tryton_rpc_client.jsonrpc import ServerProxy
p = ServerProxy(hostname, 8000, "")
print(p.common.db.list())

Integración con tests

  • Los tests de integración NO llaman Tryton real: mockean sabatron_tryton_rpc_client.client.Client.call y .connect (ver don_confiao/tests/test_products_from_tryton.py, test_categories_from_tryton.py).
  • Los probes de esta skill son solo para verificación empírica/planeación contra staging, no para la suite de tests.