This commit is contained in:
Lizandro Guarnizo
2026-05-12 19:41:17 -05:00
parent 55c68b470b
commit 25e3cd6254
9 changed files with 270 additions and 3 deletions
+117
View File
@@ -228,6 +228,123 @@ func DeleteContrato(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"message": "Eliminado", "ok": true})
}
// GetHistorialContrato devuelve la línea de tiempo de actividad de un contrato
func GetHistorialContrato(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 32)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
}
contrato, err := models.GetContratoByID(uint(id))
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
}
notifLogs, _ := models.GetLogsByContratoID(uint(id))
pagoLogs, _ := models.GetDispatchLogsByContratoID(uint(id))
// Construir timeline unificado
type Evento struct {
Tipo string `json:"tipo"` // creacion | renovacion | notificacion | pago
Icono string `json:"icono"`
Titulo string `json:"titulo"`
Detalle string `json:"detalle"`
Estado string `json:"estado"` // ok | error | info
FechaISO string `json:"fecha"`
}
var timeline []Evento
// Evento: creación del contrato
timeline = append(timeline, Evento{
Tipo: "creacion",
Icono: "document",
Titulo: "Contrato creado",
Detalle: "Inicio: " + contrato.FechaInicio.Format("02/01/2006") + " · Vence: " + contrato.FechaVencimiento.Format("02/01/2006"),
Estado: "info",
FechaISO: contrato.CreatedAt.Format(time.RFC3339),
})
// Evento: renovaciones (updated_at con estado renovado — heurístico por estado)
if contrato.Estado == "renovado" {
timeline = append(timeline, Evento{
Tipo: "renovacion",
Icono: "refresh",
Titulo: "Contrato renovado",
Detalle: "Nuevo vencimiento: " + contrato.FechaVencimiento.Format("02/01/2006"),
Estado: "ok",
FechaISO: contrato.UpdatedAt.Format(time.RFC3339),
})
}
// Eventos: notificaciones enviadas
for _, n := range notifLogs {
estado := "ok"
if n.Estado == "fallido" {
estado = "error"
} else if n.Estado == "pendiente" {
estado = "info"
}
detalle := n.Asunto
if n.Estado == "fallido" && n.ErrorMsg != "" {
detalle += " · Error: " + n.ErrorMsg
}
reglaLabel := ""
if n.Regla.ID > 0 {
reglaLabel = " (" + n.Regla.Nombre + ")"
}
timeline = append(timeline, Evento{
Tipo: "notificacion",
Icono: "mail",
Titulo: "Notificación enviada" + reglaLabel,
Detalle: detalle,
Estado: estado,
FechaISO: n.CreatedAt.Format(time.RFC3339),
})
}
// Eventos: pagos / dispatches
for _, p := range pagoLogs {
estado := "ok"
if p.Estado == "failed" {
estado = "error"
}
detalle := p.Referencia
if p.PayerEmail != "" {
detalle += " · " + p.PayerEmail
}
if p.Fuente != "" {
detalle += " · " + p.Fuente
}
timeline = append(timeline, Evento{
Tipo: "pago",
Icono: "currency",
Titulo: "Pago recibido",
Detalle: detalle,
Estado: estado,
FechaISO: p.CreatedAt.Format(time.RFC3339),
})
}
// Ordenar por fecha desc
for i := 0; i < len(timeline)-1; i++ {
for j := i + 1; j < len(timeline); j++ {
if timeline[j].FechaISO > timeline[i].FechaISO {
timeline[i], timeline[j] = timeline[j], timeline[i]
}
}
}
return c.JSON(fiber.Map{
"contrato": fiber.Map{
"id": contrato.ID,
"cliente": contrato.Cliente.Nombre,
"estado": contrato.Estado,
},
"timeline": timeline,
"total": len(timeline),
})
}
func calcularFechaVencimiento(desde time.Time, periodicidad string) time.Time {
switch periodicidad {
case "mensual":