feat: automatización de cotizaciones, contratos, actas y cuentas de cobro con IA
Implementa las 4 fases de la especificación de automatización: módulo de plantillas/tarifas editable por el equipo, generación de PDF (HTML+JS vía Chrome headless) para cotizaciones/contratos/arquitecturas/cuentas de cobro, chat propio en el dashboard reutilizando el mismo motor y tools del bot de Telegram, y nuevas tools del agente para crear estos documentos end-to-end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
772a4a5656
commit
516220a8a1
@@ -0,0 +1,79 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
// GenerarDocumentoContrato produce el PDF de un contrato ya existente a partir de
|
||||
// la plantilla activa tipo 'contrato' (cláusulas estándar) + los datos del contrato
|
||||
// (cliente, servicios, vigencia, valor). Es la implementación única que comparten
|
||||
// el endpoint POST /api/v2/contratos/:id/generar-documento y la tool crear_contrato.
|
||||
func GenerarDocumentoContrato(contratoID uint, generadoPor string) (*models.DocumentoGenerado, error) {
|
||||
contrato, err := models.GetContratoByID(contratoID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("contrato no encontrado: %w", err)
|
||||
}
|
||||
|
||||
datos := DatosBaseDocumento(map[string]interface{}{
|
||||
"Contrato": contrato,
|
||||
"Cliente": contrato.Cliente,
|
||||
"Servicios": contrato.Servicios,
|
||||
"FechaInicio": contrato.FechaInicio.Format("02/01/2006"),
|
||||
"FechaVencimiento": contrato.FechaVencimiento.Format("02/01/2006"),
|
||||
"PrecioAcordado": contrato.PrecioAcordado,
|
||||
"Moneda": contrato.Moneda,
|
||||
"Notas": contrato.Notas,
|
||||
})
|
||||
|
||||
doc, _, err := GenerarDocumento("contrato", datos, &contrato.ClienteID, nil, generadoPor)
|
||||
return doc, err
|
||||
}
|
||||
|
||||
// CrearContratoConDocumento crea el registro de contrato y de una vez genera su PDF
|
||||
// con cláusulas estándar, para el flujo "cliente, tipo de servicio, duración" que
|
||||
// describe la automatización con IA (Telegram / chat propio / Claude directo).
|
||||
func CrearContratoConDocumento(clienteID uint, servicioIDs []uint, duracionMeses int, precioAcordado float64, moneda, notas, generadoPor string) (*models.Contrato, *models.DocumentoGenerado, error) {
|
||||
if clienteID == 0 {
|
||||
return nil, nil, fmt.Errorf("cliente_id requerido")
|
||||
}
|
||||
if len(servicioIDs) == 0 {
|
||||
return nil, nil, fmt.Errorf("servicio_ids requerido (al menos un servicio)")
|
||||
}
|
||||
if duracionMeses <= 0 {
|
||||
duracionMeses = 12
|
||||
}
|
||||
if moneda == "" {
|
||||
moneda = "COP"
|
||||
}
|
||||
|
||||
inicio := time.Now()
|
||||
vencimiento := inicio.AddDate(0, duracionMeses, 0)
|
||||
|
||||
c := models.Contrato{
|
||||
ClienteID: clienteID,
|
||||
FechaInicio: inicio,
|
||||
FechaVencimiento: vencimiento,
|
||||
PrecioAcordado: precioAcordado,
|
||||
Moneda: moneda,
|
||||
Estado: "activo",
|
||||
Notas: notas,
|
||||
}
|
||||
if err := models.CreateContrato(c, servicioIDs, nil, nil, nil); err != nil {
|
||||
return nil, nil, fmt.Errorf("no se pudo crear el contrato: %w", err)
|
||||
}
|
||||
|
||||
// Recargar con Cliente/Servicios precargados (CreateContrato no los devuelve).
|
||||
creado, err := models.GetUltimoContratoByCliente(clienteID)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("contrato creado pero no se pudo recargar: %w", err)
|
||||
}
|
||||
|
||||
doc, err := GenerarDocumentoContrato(creado.ID, generadoPor)
|
||||
if err != nil {
|
||||
return creado, nil, err
|
||||
}
|
||||
return creado, doc, nil
|
||||
}
|
||||
Reference in New Issue
Block a user