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>
80 lines
2.7 KiB
Go
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
|
|
}
|