package models import ( "github.com/sujit-baniya/fiber-boilerplate/app" "gorm.io/gorm" ) // SaasApiConfig almacena la configuración del endpoint externo al que se notifica // cuando un pago es confirmado para un producto SaaS. // La vinculación es: Contrato → Servicios (m2m) → servicio_id ↔ SaasProducto.ServicioID → SaasApiConfig.SaasID type SaasApiConfig struct { gorm.Model SaasID uint `json:"saas_id" gorm:"column:saas_id;not null;index"` SaasProducto SaasProducto `json:"saas_producto" gorm:"foreignKey:SaasID"` Nombre string `json:"nombre" gorm:"column:nombre;not null"` // etiqueta amigable // Pasarela que dispara este callback: dlocal | bold | ambas (default) Pasarela string `json:"pasarela" gorm:"column:pasarela;default:'ambas'"` EndpointURL string `json:"endpoint_url" gorm:"column:endpoint_url;type:text;not null"` Metodo string `json:"metodo" gorm:"column:metodo;default:'POST'"` // POST|PUT|GET ApiKeyHeader string `json:"api_key_header" gorm:"column:api_key_header"` // ej: "X-API-Key" ApiKeyValue string `json:"api_key_value" gorm:"column:api_key_value;type:text"` // valor secreto // PayloadTemplate es un JSON con marcadores que se reemplazarán antes de enviar. // Variables disponibles: {{.ContratoID}} {{.Referencia}} {{.Email}} {{.Monto}} {{.Moneda}} {{.SaasID}} {{.SaasSlug}} {{.Fuente}} {{.WebhookToken}} PayloadTemplate string `json:"payload_template" gorm:"column:payload_template;type:text"` TimeoutSeg int `json:"timeout_seg" gorm:"column:timeout_seg;default:10"` Activo bool `json:"activo" gorm:"column:activo;default:true"` // WebhookToken es un token único por integración que identifica las llamadas entrantes // desde el SaaS externo vía POST /webhooks/saas-in/{token} WebhookToken string `json:"webhook_token" gorm:"column:webhook_token;uniqueIndex;size:64"` } func (SaasApiConfig) TableName() string { return "saas_api_configs" } // ─── SaasWebhookInLog ───────────────────────────────────────────────────────── // SaasWebhookInLog registra cada llamada entrante desde un SaaS externo // identificado por su WebhookToken único. type SaasWebhookInLog struct { gorm.Model SaasApiConfigID uint `json:"saas_api_config_id" gorm:"column:saas_api_config_id;index"` Token string `json:"token" gorm:"column:token;size:64;index"` Metodo string `json:"metodo" gorm:"column:metodo;size:10"` IP string `json:"ip" gorm:"column:ip;size:64"` Body string `json:"body" gorm:"column:body;type:text"` Headers string `json:"headers" gorm:"column:headers;type:text"` } func (SaasWebhookInLog) TableName() string { return "saas_webhook_in_logs" } // ─── SaasDispatchLog ────────────────────────────────────────────────────────── // SaasDispatchLog registra cada intento de notificación a un SaaS externo. type SaasDispatchLog struct { gorm.Model SaasApiConfigID uint `json:"saas_api_config_id" gorm:"column:saas_api_config_id;index"` SaasApiConfig SaasApiConfig `json:"saas_api_config" gorm:"foreignKey:SaasApiConfigID"` ContratoID uint `json:"contrato_id" gorm:"column:contrato_id;index"` Referencia string `json:"referencia" gorm:"column:referencia"` PayerEmail string `json:"payer_email" gorm:"column:payer_email"` Fuente string `json:"fuente" gorm:"column:fuente"` // dlocal | bold | manual HttpStatus int `json:"http_status" gorm:"column:http_status"` Respuesta string `json:"respuesta" gorm:"column:respuesta;type:text"` ErrorMsg string `json:"error_msg" gorm:"column:error_msg;type:text"` Estado string `json:"estado" gorm:"column:estado"` // success | failed Intentos int `json:"intentos" gorm:"column:intentos;default:1"` } func (SaasDispatchLog) TableName() string { return "saas_dispatch_logs" } // ─── Queries SaasApiConfig ──────────────────────────────────────────────────── func GetAllSaasApiConfigs(limit, offset int) ([]SaasApiConfig, int64, error) { var items []SaasApiConfig var total int64 db := app.Http.Database.DB.Model(&SaasApiConfig{}).Preload("SaasProducto") if err := db.Count(&total).Error; err != nil { return nil, 0, err } if err := db.Order("created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil { return nil, 0, err } return items, total, nil } func GetSaasApiConfigByID(id uint) (*SaasApiConfig, error) { var item SaasApiConfig if err := app.Http.Database.DB.Preload("SaasProducto").First(&item, id).Error; err != nil { return nil, err } return &item, nil } // GetSaasApiConfigsBySaasIDs devuelve configuraciones activas para los saas_ids dados, // opcionalmente filtradas por pasarela ("dlocal", "bold" o "" para todas). func GetSaasApiConfigsBySaasIDs(saasIDs []uint, pasarela string) ([]SaasApiConfig, error) { if len(saasIDs) == 0 { return nil, nil } db := app.Http.Database.DB. Preload("SaasProducto"). Where("saas_id IN ? AND activo = ?", saasIDs, true) if pasarela != "" { db = db.Where("pasarela = ? OR pasarela = 'ambas'", pasarela) } var items []SaasApiConfig if err := db.Find(&items).Error; err != nil { return nil, err } return items, nil } func CreateSaasApiConfig(item *SaasApiConfig) error { return app.Http.Database.DB.Create(item).Error } func UpdateSaasApiConfig(item *SaasApiConfig) error { return app.Http.Database.DB.Save(item).Error } func DeleteSaasApiConfig(id uint) error { return app.Http.Database.DB.Delete(&SaasApiConfig{}, id).Error } // GetSaasApiConfigByWebhookToken busca una integración por su token de webhook entrante. func GetSaasApiConfigByWebhookToken(token string) (*SaasApiConfig, error) { var item SaasApiConfig if err := app.Http.Database.DB.Preload("SaasProducto"). Where("webhook_token = ? AND activo = true", token). First(&item).Error; err != nil { return nil, err } return &item, nil } // SaveSaasWebhookInLog persiste un log de webhook entrante. func SaveSaasWebhookInLog(entry *SaasWebhookInLog) error { return app.Http.Database.DB.Create(entry).Error } // ─── Queries SaasDispatchLog ────────────────────────────────────────────────── func SaveSaasDispatchLog(entry *SaasDispatchLog) error { return app.Http.Database.DB.Create(entry).Error } func GetSaasDispatchLogs(limit, offset int) ([]SaasDispatchLog, int64, error) { var items []SaasDispatchLog var total int64 db := app.Http.Database.DB.Model(&SaasDispatchLog{}).Preload("SaasApiConfig") if err := db.Count(&total).Error; err != nil { return nil, 0, err } if err := db.Order("created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil { return nil, 0, err } return items, total, nil } // GetDispatchLogsByContratoID devuelve los pagos/dispatches de un contrato específico func GetDispatchLogsByContratoID(contratoID uint) ([]SaasDispatchLog, error) { var items []SaasDispatchLog if err := app.Http.Database.DB. Where("contrato_id = ?", contratoID). Order("created_at DESC"). Limit(50). Find(&items).Error; err != nil { return nil, err } return items, nil }