feat(umind): el agente emite cotizaciones y contratos con la plantilla del cliente
El motor de PDF ya existía entero para el staff — Chrome headless, text/template
con {{range .Items}}, y hasta el importador que convierte un Word en plantilla
con IA. Lo único que faltaba era que fueran de cada cliente.
PlantillaDocumento gana TenantID *uint: nulo = global del staff (lo de
siempre), con valor = del espacio. Mismo patrón exacto que AiConfig, el que ya
tiene su lección aprendida. Y GetPlantillaDocumentoActiva ahora filtra
tenant_id IS NULL explícitamente: sin eso, la plantilla que un cliente escribe
para su propio contrato podía salir en un documento de la empresa. Hay test.
Un cliente sin plantilla propia cae a la global, así puede emitir una
cotización desde el primer día y personalizarla cuando quiera. Guardar crea
versión nueva en vez de pisar la vieja: si la nueva sale mal, la anterior sigue
ahí. Y se valida que compile ANTES de guardar — una plantilla rota descubierta
al generar deja al cliente esperando un PDF que nunca llega.
La tool solo se le ofrece al modelo si hay alguna plantilla disponible:
prometerle una capacidad que después falla es peor que no tenerla.
El semáforo de tres: cada PDF levanta un Chrome entero, y cien clientes
generando a la vez son cien navegadores. Eso tira el servidor mucho antes que
cualquier consulta a la IA, así que va desde el día uno y no cuando se caiga.
El JSON de ítems mal formado no tumba la generación — sale el documento sin la
tabla, que todavía se puede corregir a mano. Y sin cantidad se asume 1: el
modelo la omite seguido, y un total en cero es peor que uno aproximado.
Cada documento se cobra (levanta un Chrome) y queda en los archivos del
espacio, descargable como cualquier otro.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
544cba6d34
commit
047837dd23
@@ -57,6 +57,13 @@ func umindTools(agenteID uint, sesionInterna bool) []agentTool {
|
||||
},
|
||||
}}
|
||||
|
||||
// Generar documentos está disponible siempre: preparar un borrador es
|
||||
// barato y reversible. Lo que espera aprobación es entregarlo, y de eso
|
||||
// se encarga la puerta de executeUmindTool.
|
||||
if models.TienePlantillasDocumento(agenteID) {
|
||||
tools = append(tools, umindDocumentoTools()...)
|
||||
}
|
||||
|
||||
// Los avisos solo existen para el dueño. En el widget público escribe
|
||||
// cualquiera, y programar recordatorios gasta el plan de otro.
|
||||
if sesionInterna {
|
||||
@@ -179,6 +186,10 @@ func ejecutarHerramienta(agenteID uint, sessionID string, sesionInterna bool, na
|
||||
return executeUmindEmailTool(agenteID, name, args)
|
||||
}
|
||||
|
||||
if name == "generar_documento" {
|
||||
return executeUmindDocumentoTool(agenteID, args)
|
||||
}
|
||||
|
||||
if strings.HasSuffix(name, "_aviso") || name == "listar_avisos" {
|
||||
if !sesionInterna {
|
||||
return `{"error": "los recordatorios solo puede programarlos el dueño desde su canal privado"}`
|
||||
|
||||
Reference in New Issue
Block a user