Files
soft_usite/pkg/services/contrato_documento_service.go
T
Lizandro GDandClaude Sonnet 5 516220a8a1 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>
2026-08-03 00:45:58 +00:00

80 lines
2.7 KiB
Go

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
}