Files
soft_usite/rest/controllers/contrato_controller.go
T

220 lines
6.7 KiB
Go

package controllers
import (
"math"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
)
func ContratosView(c *fiber.Ctx) error {
return c.Render("renovaciones/contratos", fiber.Map{
"user": c.Locals("user"),
"modules": c.Locals("userModules"),
}, "layouts/main")
}
func GetContratos(c *fiber.Ctx) error {
page, _ := strconv.Atoi(c.Query("page", "1"))
limit, _ := strconv.Atoi(c.Query("limit", "10"))
if page < 1 {
page = 1
}
offset := (page - 1) * limit
records, total, err := models.GetAllContratos(limit, offset, c.Query("search"), c.Query("estado"))
if err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
// Enriquecer con días restantes
type ContratoDTO struct {
models.Contrato
DiasRestantes int `json:"dias_restantes"`
Urgencia string `json:"urgencia"` // verde | amarillo | rojo
PrecioSugerido float64 `json:"precio_sugerido"`
}
dtos := make([]ContratoDTO, len(records))
now := time.Now()
for i, r := range records {
dias := int(r.FechaVencimiento.Sub(now).Hours() / 24)
urgencia := "verde"
if dias <= 0 {
urgencia = "rojo"
} else if dias <= 30 {
urgencia = "amarillo"
}
var sugerido float64
for _, s := range r.Servicios {
sugerido += s.Precio
}
dtos[i] = ContratoDTO{Contrato: r, DiasRestantes: dias, Urgencia: urgencia, PrecioSugerido: sugerido}
}
return c.JSON(fiber.Map{
"registros": dtos,
"total": total,
"totalPages": int(math.Ceil(float64(total) / float64(limit))),
"page": page,
"limit": limit,
})
}
func CreateContrato(c *fiber.Ctx) error {
type Input struct {
ClienteID uint `json:"cliente_id"`
ServicioIDs []uint `json:"servicio_ids"`
FechaInicio string `json:"fecha_inicio"`
FechaVencimiento string `json:"fecha_vencimiento"`
PrecioAcordado float64 `json:"precio_acordado"`
AutoRenovar bool `json:"auto_renovar"`
Notas string `json:"notas"`
}
var inp Input
if err := c.BodyParser(&inp); err != nil {
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
}
fi, err := time.Parse("2006-01-02", inp.FechaInicio)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Fecha inicio inválida"})
}
fv, err := time.Parse("2006-01-02", inp.FechaVencimiento)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Fecha vencimiento inválida"})
}
m := models.Contrato{
ClienteID: inp.ClienteID,
FechaInicio: fi,
FechaVencimiento: fv,
PrecioAcordado: inp.PrecioAcordado,
AutoRenovar: inp.AutoRenovar,
Notas: inp.Notas,
Estado: "activo",
}
if err := models.CreateContrato(m, inp.ServicioIDs); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.Status(201).JSON(fiber.Map{"message": "Contrato creado", "ok": true})
}
func UpdateContrato(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"})
}
type Input struct {
ServicioIDs []uint `json:"servicio_ids"`
Estado string `json:"estado"`
FechaVencimiento string `json:"fecha_vencimiento"`
PrecioAcordado float64 `json:"precio_acordado"`
AutoRenovar bool `json:"auto_renovar"`
Notas string `json:"notas"`
}
var inp Input
if err := c.BodyParser(&inp); err != nil {
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
}
existing, err := models.GetContratoByID(uint(id))
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
}
if inp.FechaVencimiento != "" {
fv, err := time.Parse("2006-01-02", inp.FechaVencimiento)
if err == nil {
existing.FechaVencimiento = fv
}
}
if inp.Estado != "" {
existing.Estado = inp.Estado
}
existing.PrecioAcordado = inp.PrecioAcordado
existing.AutoRenovar = inp.AutoRenovar
existing.Notas = inp.Notas
if err := models.UpdateContrato(*existing, inp.ServicioIDs); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Actualizado", "ok": true})
}
func RenovarContrato(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"})
}
existing, err := models.GetContratoByID(uint(id))
if err != nil {
return c.Status(404).JSON(fiber.Map{"error": "No encontrado"})
}
// Usar periodicidad del primer servicio asociado
periodicidad := ""
if len(existing.Servicios) > 0 {
periodicidad = existing.Servicios[0].Periodicidad
}
nuevaInicio := existing.FechaVencimiento.AddDate(0, 0, 1)
nuevaVenc := calcularFechaVencimiento(nuevaInicio, periodicidad)
// Copiar IDs de servicios del contrato anterior
var servicioIDs []uint
for _, s := range existing.Servicios {
servicioIDs = append(servicioIDs, s.ID)
}
nuevo := models.Contrato{
ClienteID: existing.ClienteID,
FechaInicio: nuevaInicio,
FechaVencimiento: nuevaVenc,
PrecioAcordado: existing.PrecioAcordado,
AutoRenovar: existing.AutoRenovar,
Estado: "activo",
Notas: "Renovación automática desde contrato #" + strconv.Itoa(int(existing.ID)),
}
if err := models.CreateContrato(nuevo, servicioIDs); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
// Marcar anterior como renovado
existing.Estado = "renovado"
models.UpdateContrato(*existing, nil)
return c.JSON(fiber.Map{"message": "Renovado", "ok": true})
}
func EnviarCorreoContrato(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"})
}
if err := services.EnviarCorreoManual(contrato); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Correo enviado", "ok": true})
}
func DeleteContrato(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"})
}
if err := models.DeleteContrato(uint(id)); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"message": "Eliminado", "ok": true})
}
func calcularFechaVencimiento(desde time.Time, periodicidad string) time.Time {
switch periodicidad {
case "mensual":
return desde.AddDate(0, 1, 0)
case "trimestral":
return desde.AddDate(0, 3, 0)
case "semestral":
return desde.AddDate(0, 6, 0)
case "anual":
return desde.AddDate(1, 0, 0)
default:
return desde.AddDate(1, 0, 0)
}
}