Files
soft_usite/pkg/models/bold_config.go
T

107 lines
4.2 KiB
Go

package models
import (
"github.com/sujit-baniya/fiber-boilerplate/app"
"gorm.io/gorm"
)
// BoldConfig almacena las credenciales de Bold (pasarela de pagos colombiana).
// Solo un registro puede estar activo a la vez.
type BoldConfig struct {
gorm.Model
// Claves de producción
ApiKeyProd string `json:"api_key_prod" gorm:"column:api_key_prod;type:text"`
SecretKeyProd string `json:"secret_key_prod" gorm:"column:secret_key_prod;type:text"`
// Claves de prueba / test
ApiKeyTest string `json:"api_key_test" gorm:"column:api_key_test;type:text"`
// En modo test la secret key es cadena vacía según la doc oficial
SecretKeyTest string `json:"secret_key_test" gorm:"column:secret_key_test;type:text"`
// Modo activo: "test" | "production"
Modo string `json:"modo" gorm:"column:modo;default:'test'"`
// URL a la que Bold redirige al usuario tras el pago
CallbackUrl string `json:"callback_url" gorm:"column:callback_url;type:text"`
// Nota interna
Nota string `json:"nota" gorm:"column:nota;type:text"`
Activo bool `json:"activo" gorm:"column:activo;default:true"`
}
func (BoldConfig) TableName() string { return "bold_config" }
// GetBoldConfig retorna la configuración activa.
func GetBoldConfig() (*BoldConfig, error) {
var item BoldConfig
if err := app.Http.Database.DB.Where("activo = ?", true).Order("id DESC").First(&item).Error; err != nil {
return nil, err
}
return &item, nil
}
// SaveBoldConfig desactiva la config previa y guarda la nueva (o actualiza si ya tiene ID).
func SaveBoldConfig(s BoldConfig) error {
app.Http.Database.DB.Model(&BoldConfig{}).
Where("activo = ?", true).
Update("activo", false)
s.Activo = true
if s.ID > 0 {
return app.Http.Database.DB.Model(&s).Updates(map[string]interface{}{
"api_key_prod": s.ApiKeyProd,
"secret_key_prod": s.SecretKeyProd,
"api_key_test": s.ApiKeyTest,
"secret_key_test": s.SecretKeyTest,
"modo": s.Modo,
"callback_url": s.CallbackUrl,
"nota": s.Nota,
"activo": true,
}).Error
}
return app.Http.Database.DB.Create(&s).Error
}
// ─── Webhook log para idempotencia ───────────────────────────────────────────
// BoldWebhookLog registra cada notificación recibida de Bold.
// La restricción UNIQUE sobre notification_id evita procesar duplicados.
type BoldWebhookLog struct {
gorm.Model
NotificationID string `json:"notification_id" gorm:"column:notification_id;uniqueIndex;type:varchar(64);not null"`
Tipo string `json:"tipo" gorm:"column:tipo;type:varchar(30)"`
PaymentID string `json:"payment_id" gorm:"column:payment_id;type:varchar(64)"`
Referencia string `json:"referencia" gorm:"column:referencia;type:varchar(120)"`
PayerEmail string `json:"payer_email" gorm:"column:payer_email;type:varchar(255)"`
Monto int64 `json:"monto" gorm:"column:monto"`
Procesado bool `json:"procesado" gorm:"column:procesado;default:false"`
// Body crudo del webhook para auditoría
Raw string `json:"raw" gorm:"column:raw;type:text"`
}
func (BoldWebhookLog) TableName() string { return "bold_webhook_log" }
// IsBoldNotificationDuplicate intenta insertar el log. Devuelve true si ya existía.
func IsBoldNotificationDuplicate(notificationID string) bool {
result := app.Http.Database.DB.
Where("notification_id = ?", notificationID).
First(&BoldWebhookLog{})
return result.Error == nil // nil error = registro encontrado = duplicado
}
// SaveBoldWebhookLog guarda el log del webhook.
func SaveBoldWebhookLog(entry BoldWebhookLog) error {
return app.Http.Database.DB.Create(&entry).Error
}
// MarkBoldWebhookProcessed marca la notificación como procesada.
func MarkBoldWebhookProcessed(notificationID string) {
app.Http.Database.DB.Model(&BoldWebhookLog{}).
Where("notification_id = ?", notificationID).
Update("procesado", true)
}
// GetBoldWebhookLogs devuelve los últimos N registros del log.
func GetBoldWebhookLogs(limit int) ([]BoldWebhookLog, error) {
var logs []BoldWebhookLog
if err := app.Http.Database.DB.Order("id DESC").Limit(limit).Find(&logs).Error; err != nil {
return nil, err
}
return logs, nil
}