Files
soft_usite/pkg/models/contrato.go
T

137 lines
4.5 KiB
Go

package models
import (
"log"
"time"
"github.com/sujit-baniya/fiber-boilerplate/app"
"gorm.io/gorm"
)
type Contrato struct {
gorm.Model
ClienteID uint `json:"cliente_id" gorm:"column:cliente_id"`
Cliente Cliente `json:"cliente" gorm:"foreignKey:ClienteID"`
Servicios []Servicio `json:"servicios" gorm:"many2many:contrato_servicios"`
FechaInicio time.Time `json:"fecha_inicio" gorm:"column:fecha_inicio"`
FechaVencimiento time.Time `json:"fecha_vencimiento" gorm:"column:fecha_vencimiento"`
PrecioAcordado float64 `json:"precio_acordado" gorm:"column:precio_acordado"`
Estado string `json:"estado" gorm:"column:estado;default:'activo'"` // activo | vencido | cancelado | renovado
AutoRenovar bool `json:"auto_renovar" gorm:"column:auto_renovar;default:false"`
Notas string `json:"notas" gorm:"column:notas"`
}
func (Contrato) TableName() string { return "contratos" }
func GetAllContratos(limit, offset int, search, estado string) ([]Contrato, int64, error) {
var items []Contrato
var total int64
db := app.Http.Database.DB.Model(&Contrato{}).
Preload("Cliente").Preload("Servicios")
if search != "" {
db = db.Joins("JOIN clientes ON clientes.id = contratos.cliente_id").
Where("clientes.nombre ILIKE ? OR clientes.empresa ILIKE ?",
"%"+search+"%", "%"+search+"%")
}
if estado != "" {
db = db.Where("contratos.estado = ?", estado)
}
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
if err := db.Order("contratos.fecha_vencimiento ASC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
return nil, 0, err
}
return items, total, nil
}
func GetContratoByID(id uint) (*Contrato, error) {
var item Contrato
if err := app.Http.Database.DB.Preload("Cliente").Preload("Servicios").First(&item, id).Error; err != nil {
return nil, err
}
return &item, nil
}
// GetContratosByCliente devuelve contratos de un cliente específico
func GetContratosByCliente(clienteID uint) ([]Contrato, error) {
var items []Contrato
if err := app.Http.Database.DB.Preload("Servicios").
Where("cliente_id = ?", clienteID).
Order("fecha_vencimiento ASC").Find(&items).Error; err != nil {
return nil, err
}
return items, nil
}
// GetContratosProximosVencer retorna contratos activos que vencen exactamente en N días
func GetContratosProximosVencer(diasAntes int) ([]Contrato, error) {
var items []Contrato
target := time.Now().AddDate(0, 0, diasAntes).UTC()
startOfDay := time.Date(target.Year(), target.Month(), target.Day(), 0, 0, 0, 0, time.UTC)
endOfDay := startOfDay.Add(24 * time.Hour)
if err := app.Http.Database.DB.Preload("Cliente").Preload("Servicios").
Where("estado = 'activo' AND fecha_vencimiento >= ? AND fecha_vencimiento < ?", startOfDay, endOfDay).
Find(&items).Error; err != nil {
log.Printf("Error getting contratos proximos: %v", err)
return nil, err
}
return items, nil
}
// syncContratoServicios sincroniza la tabla join contrato_servicios usando SQL directo
// para evitar que GORM intente hacer upsert de los servicios existentes.
func syncContratoServicios(contratoID uint, servicioIDs []uint) error {
db := app.Http.Database.DB
if err := db.Exec("DELETE FROM contrato_servicios WHERE contrato_id = ?", contratoID).Error; err != nil {
return err
}
for _, sid := range servicioIDs {
if err := db.Exec(
"INSERT INTO contrato_servicios (contrato_id, servicio_id) VALUES (?, ?) ON CONFLICT DO NOTHING",
contratoID, sid,
).Error; err != nil {
return err
}
}
return nil
}
func CreateContrato(c Contrato, servicioIDs []uint) error {
db := app.Http.Database.DB
if err := db.Omit("Servicios.*").Create(&c).Error; err != nil {
return err
}
return syncContratoServicios(c.ID, servicioIDs)
}
func UpdateContrato(c Contrato, servicioIDs []uint) error {
db := app.Http.Database.DB
if err := db.Model(&Contrato{}).Where("id = ?", c.ID).Updates(map[string]interface{}{
"cliente_id": c.ClienteID,
"fecha_inicio": c.FechaInicio,
"fecha_vencimiento": c.FechaVencimiento,
"precio_acordado": c.PrecioAcordado,
"estado": c.Estado,
"auto_renovar": c.AutoRenovar,
"notas": c.Notas,
}).Error; err != nil {
return err
}
if servicioIDs != nil {
return syncContratoServicios(c.ID, servicioIDs)
}
return nil
}
func DeleteContrato(id uint) error {
db := app.Http.Database.DB
var c Contrato
if err := db.First(&c, id).Error; err != nil {
return err
}
db.Exec("DELETE FROM contrato_servicios WHERE contrato_id = ?", id)
return db.Delete(&c).Error
}