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"` ServicioID uint `json:"servicio_id" gorm:"column:servicio_id"` Servicio Servicio `json:"servicio" gorm:"foreignKey:ServicioID"` 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("Servicio") 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("Servicio").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("Servicio"). 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("Servicio"). 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 } func CreateContrato(c Contrato) error { return app.Http.Database.DB.Create(&c).Error } func UpdateContrato(c Contrato) error { return app.Http.Database.DB.Model(&c).Updates(c).Error } func DeleteContrato(id uint) error { var c Contrato if err := app.Http.Database.DB.First(&c, id).Error; err != nil { return err } return app.Http.Database.DB.Delete(&c).Error }