fix: tareas del agente invisibles en el Kanban + facturas de compra por Telegram
- El agente creaba tareas con estado='pendiente' (default), pero el tablero Kanban del dashboard solo reconoce por_hacer/en_progreso/revision/hecho. La tarea se guardaba bien (por eso llegaba el correo de notificación) pero no aparecía en ninguna columna. Se corrigen los enums y el default de las tools crear_tarea/actualizar_estado_tarea, y se agrega una reparación única al arranque que corrige las tareas ya creadas con el estado inválido. - adjuntar_factura siempre asumía factura de VENTA (ligada a un cliente). Se agrega adjuntar_factura_compra: cuando un proveedor le factura a U-SITE (no al revés), busca/crea la Entidad proveedor y registra una cuenta por pagar con el documento adjunto (se agregan campos archivo/original_name/tipo_mime a CuentaPagar, que no los tenía). El prompt del sistema instruye a Claude a decidir la dirección leyendo quién emite y quién recibe el documento. De paso: endpoint de descarga del soporte de la factura de compra, expuesto también en el dashboard (/app/contabilidad/cuentas-pagar). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c8e5afceb2
commit
5ac70a4d6e
@@ -167,13 +167,19 @@ func agentTools() []agentTool {
|
||||
"search": str("Búsqueda por número, cliente o descripción"),
|
||||
"estado": agentToolParam{Type: "string", Description: "pendiente | pagada | vencida | cancelada", Enum: []string{"pendiente", "pagada", "vencida", "cancelada", ""}},
|
||||
}, nil)),
|
||||
tool("adjuntar_factura", "Guarda como factura el documento (PDF/foto) que el usuario acaba de enviar por Telegram en este chat. Solo funciona si hay un archivo adjunto pendiente; si no lo hay, pide al usuario que lo reenvíe.",
|
||||
tool("adjuntar_factura", "Guarda como factura de VENTA el documento (PDF/foto) que el usuario acaba de enviar por Telegram: U-SITE es quien factura/cobra al cliente. Solo funciona si hay un archivo adjunto pendiente. Si el documento es al revés (un proveedor le factura a U-SITE), usa adjuntar_factura_compra en su lugar, no esta.",
|
||||
obj(map[string]agentToolParam{
|
||||
"cliente_id": num("ID del cliente al que pertenece la factura (usa listar_clientes si no lo sabes)"),
|
||||
"numero": str("Número de factura, si el usuario lo indicó"),
|
||||
"monto": num("Monto de la factura, si el usuario lo indicó"),
|
||||
"descripcion": str("Descripción breve, ej: 'Factura mensual octubre'"),
|
||||
}, []string{"cliente_id"})),
|
||||
tool("adjuntar_factura_compra", "Guarda como factura de COMPRA (cuenta por pagar) el documento que el usuario acaba de enviar por Telegram: un proveedor le está facturando a U-SITE, no al revés. Busca o crea el proveedor por nombre. Solo funciona si hay un archivo adjunto pendiente.",
|
||||
obj(map[string]agentToolParam{
|
||||
"proveedor": str("Nombre del proveedor que emitió la factura (quien la firma/factura, no U-SITE)"),
|
||||
"monto": num("Monto de la factura"),
|
||||
"descripcion": str("Descripción breve de la compra, ej: 'Hosting AWS octubre'"),
|
||||
}, []string{"proveedor", "monto"})),
|
||||
|
||||
// ── Clientes ─────────────────────────────────────────────────────────
|
||||
tool("listar_clientes", "Lista clientes con paginación y búsqueda.",
|
||||
@@ -346,7 +352,7 @@ func agentTools() []agentTool {
|
||||
obj(map[string]agentToolParam{
|
||||
"titulo": str("Título de la tarea"),
|
||||
"descripcion": str("Descripción"),
|
||||
"estado": agentToolParam{Type: "string", Enum: []string{"pendiente", "en_progreso"}, Description: "Estado inicial"},
|
||||
"estado": agentToolParam{Type: "string", Enum: []string{"por_hacer", "en_progreso"}, Description: "Estado inicial (default por_hacer). Debe coincidir con las columnas del tablero Kanban."},
|
||||
"prioridad": agentToolParam{Type: "string", Enum: []string{"baja", "media", "alta"}, Description: "Prioridad"},
|
||||
"asignado_id": num("ID del usuario responsable (usa listar_usuarios si no lo sabes)"),
|
||||
"fecha_limite": str("Fecha límite, formato YYYY-MM-DD"),
|
||||
@@ -356,10 +362,14 @@ func agentTools() []agentTool {
|
||||
"id": num("ID de la tarea"),
|
||||
"asignado_id": num("ID del usuario responsable (usa listar_usuarios si no lo sabes)"),
|
||||
}, []string{"id", "asignado_id"})),
|
||||
tool("actualizar_estado_tarea", "Cambia el estado de una tarea.",
|
||||
tool("actualizar_estado_tarea", "Cambia el estado de una tarea. Los valores deben coincidir con las columnas del tablero Kanban del dashboard.",
|
||||
obj(map[string]agentToolParam{
|
||||
"id": num("ID de la tarea"),
|
||||
"estado": agentToolParam{Type: "string", Enum: []string{"pendiente", "en_progreso", "completada", "cancelada"}, Description: "Nuevo estado"},
|
||||
"id": num("ID de la tarea"),
|
||||
"estado": agentToolParam{
|
||||
Type: "string",
|
||||
Enum: []string{"por_hacer", "en_progreso", "revision", "hecho"},
|
||||
Description: "por_hacer=nueva, en_progreso=en curso, revision=terminada pendiente de revisar, hecho=cerrada",
|
||||
},
|
||||
}, []string{"id", "estado"})),
|
||||
|
||||
// ── Servidores ───────────────────────────────────────────────────────
|
||||
@@ -617,6 +627,13 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
}
|
||||
return map[string]interface{}{"ok": true, "factura_id": f.ID}, nil
|
||||
|
||||
case "adjuntar_factura_compra":
|
||||
cp, err := AdjuntarFacturaCompra(chatID, getStr("proveedor"), getStr("descripcion"), float64(getInt("monto", 0)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]interface{}{"ok": true, "cuenta_pagar_id": cp.ID, "proveedor_id": cp.EntidadID}, nil
|
||||
|
||||
case "listar_clientes":
|
||||
page := getInt("page", 1)
|
||||
search := getStr("search")
|
||||
@@ -1478,7 +1495,7 @@ COMPORTAMIENTO:
|
||||
- Si una herramienta falla, explica el error y sugiere alternativas
|
||||
- En Coolify: si solo hay una instancia activa se usa automáticamente, no hace falta preguntar por config_id; si hay varias, consulta coolify_instancias y pregunta cuál. Para actuar sobre algo necesitas su UUID: búscalo con coolify_listar por nombre antes de llamar a coolify_accion. Reiniciar/desplegar es rutinario, hazlo directo; detener algo en producción sí confírmalo antes. Si un despliegue falla, revisa coolify_logs y coolify_deployments para explicar la causa concreta
|
||||
- Cuando el mensaje empiece con "[Documento adjunto recibido: ...]", el usuario acaba de enviar un PDF o foto por Telegram y puedes leerlo directamente (está adjunto a este mismo mensaje, no es solo un nombre de archivo). Decide primero de qué se trata el archivo antes de guardarlo:
|
||||
· Si es una factura/cuenta de cobro → identifica cliente, monto y número, resuelve el cliente_id con listar_clientes, y llama a adjuntar_factura
|
||||
· Si es una factura → primero determina la dirección leyendo quién emite y quién recibe: si el emisor/vendedor es "U-Site S.A.S BIC" (o similar) y el destinatario es un cliente, es una factura de VENTA → identifica cliente, monto y número, resuelve el cliente_id con listar_clientes, y llama a adjuntar_factura. Si es al revés — un proveedor (AWS, Coolify, un hosting, cualquier tercero) le está facturando A U-Site — es una factura de COMPRA → llama a adjuntar_factura_compra con el nombre de ese proveedor, no busques cliente_id. Ante la duda, mira a nombre de quién sale la plata: si U-Site cobra, es venta; si U-Site paga, es compra
|
||||
· Si es un documento de un proyecto (contrato, orden de servicio, entregable, etc.) → identifica a qué proyecto corresponde (usa listar_proyectos si hace falta) y llama a adjuntar_documento_proyecto
|
||||
Si logras identificar los datos necesarios (del documento o de lo que escribió el usuario), guarda directamente sin pedir confirmación — solo pregunta si de verdad no hay forma de determinar el cliente/proyecto o falta un dato imprescindible. No uses estas tools si el mensaje no menciona ningún documento adjunto
|
||||
- Para registrar un proyecto nuevo con sus fases (el usuario puede describirlo en texto o mandarlo en un documento), primero usa crear_proyecto y luego llama a crear_fase_proyecto una vez por cada fase que corresponda — no hace falta preguntar confirmación entre cada fase
|
||||
|
||||
Reference in New Issue
Block a user