package models import ( "log" "github.com/sujit-baniya/fiber-boilerplate/app" "gorm.io/gorm" ) type DlocalApi struct { gorm.Model AccessKeyID string `gorm:"not null" json:"access_key_id"` // Access Key ID AccessKeySecret string `gorm:"not null" json:"access_key_secret"` // Access Key Secret AccessKeyIDdev string `gorm:"not null" json:"access_key_id_dev"` // Access Key ID AccessKeySecretdev string `gorm:"not null" json:"access_key_secret_dev"` IsActive bool `gorm:"default:true" json:"is_active"` // Activar o desactivar config UrlDev string `gorm:"type:text" json:"url_dev"` UrlProd string `gorm:"type:text" json:"url_prod"` Modo string `gorm:"default:'prod'" json:"modo"` } type PlanRequest struct { Name string `json:"name" validate:"required"` Description string `json:"description" validate:"required"` Currency string `json:"currency" validate:"required"` Amount float64 `json:"amount" validate:"required"` FrequencyType string `json:"frequency_type" validate:"required"` Country string `json:"country,omitempty"` FrequencyValue int `json:"frequency_value,omitempty"` DayOfMonth int `json:"day_of_month,omitempty"` NotificationURL string `json:"notification_url,omitempty"` SuccessURL string `json:"success_url,omitempty"` BackURL string `json:"back_url,omitempty"` ErrorURL string `json:"error_url,omitempty"` } // TableName asegura que GORM use la tabla 'qrvcard' func (DlocalApi) TableName() string { return "dlocal_api" } // GetAllQrVcard obtiene todos los registros de QrVcard con paginación y búsqueda func GetAllDlocalApi(limit, offset int, search string) ([]DlocalApi, int64, error) { var items []DlocalApi var total int64 db := app.Http.Database.DB.Model(&DlocalApi{}) // Contamos el total de registros if err := db.Count(&total).Error; err != nil { log.Printf("Error counting DlocalApi: %v", err) return nil, 0, err } // Obtenemos los registros con paginación if err := db.Order("id DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil { log.Printf("Error retrieving DlocalApi: %v", err) return nil, 0, err } return items, total, nil } // CreateQrVcard crea un nuevo registro de QrVcard en la base de datos func CreateDlocalApi(DlocalApi *DlocalApi) error { if err := app.Http.Database.DB.Create(&DlocalApi).Error; err != nil { return err } return nil } // UpdateQrVcard actualiza un registro de QrVcard existente func UpdateDlocalApi(DlocalApi *DlocalApi) error { if err := app.Http.Database.DB.Model(&DlocalApi).Updates(DlocalApi).Error; err != nil { return err } return nil } // DeleteQrVcard elimina un registro de QrVcard de la base de datos func DeleteDlocalApi(DlocalApi *DlocalApi) error { if err := app.Http.Database.DB.Delete(&DlocalApi).Error; err != nil { return err } return nil } // GetLastActiveDlocalApi obtiene el último registro activo func GetLastActiveDlocalApi() (*DlocalApi, error) { var dlocalConfig DlocalApi err := app.Http.Database.DB. Where("is_active = ?", true). Order("id DESC"). First(&dlocalConfig).Error if err != nil { return nil, err } return &dlocalConfig, nil } // ─── DlocalPaymentLog ───────────────────────────────────────────────────────── // DlocalPaymentLog registra cada pago/notificación de dLocal. // Cubre webhooks automáticos y registros manuales del backoffice. type DlocalPaymentLog struct { gorm.Model // notification_id único; para entradas manuales se genera con prefijo "manual-" NotificationID string `json:"notification_id" gorm:"column:notification_id;uniqueIndex;type:varchar(128);not null"` Fuente string `json:"fuente" gorm:"column:fuente;type:varchar(20)"` // "webhook" | "manual" Tipo string `json:"tipo" gorm:"column:tipo;type:varchar(50)"` // PAYMENT, SUBSCRIPTION_CHARGE, … Estado string `json:"estado" gorm:"column:estado;type:varchar(30)"` // PAID, PENDING, REJECTED, CANCELLED, EXPIRED PaymentID string `json:"payment_id" gorm:"column:payment_id;type:varchar(64)"` OrderID string `json:"order_id" gorm:"column:order_id;type:varchar(120)"` Referencia string `json:"referencia" gorm:"column:referencia;type:varchar(120)"` PayerEmail string `json:"payer_email" gorm:"column:payer_email;type:varchar(255)"` Monto float64 `json:"monto" gorm:"column:monto"` Moneda string `json:"moneda" gorm:"column:moneda;type:varchar(10)"` Procesado bool `json:"procesado" gorm:"column:procesado;default:false"` Nota string `json:"nota" gorm:"column:nota;type:text"` Raw string `json:"raw" gorm:"column:raw;type:text"` } func (DlocalPaymentLog) TableName() string { return "dlocal_payment_log" } // IsDlocalNotificationDuplicate devuelve true si el notification_id ya existe. func IsDlocalNotificationDuplicate(notificationID string) bool { result := app.Http.Database.DB. Where("notification_id = ?", notificationID). First(&DlocalPaymentLog{}) return result.Error == nil } // SaveDlocalPaymentLog inserta un nuevo registro de pago. func SaveDlocalPaymentLog(entry DlocalPaymentLog) error { return app.Http.Database.DB.Create(&entry).Error } // MarkDlocalPaymentProcessed marca el registro como procesado. func MarkDlocalPaymentProcessed(notificationID string) { app.Http.Database.DB.Model(&DlocalPaymentLog{}). Where("notification_id = ?", notificationID). Update("procesado", true) } // GetDlocalPaymentLogs devuelve los últimos N registros ordenados por fecha. func GetDlocalPaymentLogs(limit int) ([]DlocalPaymentLog, error) { var logs []DlocalPaymentLog if err := app.Http.Database.DB.Order("id DESC").Limit(limit).Find(&logs).Error; err != nil { return nil, err } return logs, nil } // GetDlocalPaymentLogsPaginated devuelve los logs con paginación y filtro por estado. // El valor especial "APROBADOS" agrupa PAID + AUTHORIZED. func GetDlocalPaymentLogsPaginated(page, limit int, estado string) ([]DlocalPaymentLog, int64, error) { var logs []DlocalPaymentLog var total int64 db := app.Http.Database.DB.Model(&DlocalPaymentLog{}) switch estado { case "", "TODOS": // sin filtro case "APROBADOS": db = db.Where("estado IN ?", []string{"PAID", "AUTHORIZED"}) default: db = db.Where("estado = ?", estado) } db.Count(&total) offset := (page - 1) * limit if err := db.Order("id DESC").Limit(limit).Offset(offset).Find(&logs).Error; err != nil { return nil, 0, err } return logs, total, nil } // GetDlocalPaymentLogByID carga un registro por su PK. func GetDlocalPaymentLogByID(id uint, out *DlocalPaymentLog) error { return app.Http.Database.DB.First(out, id).Error } // UpdateDlocalPaymentLogDatos actualiza email y monto de un log existente. func UpdateDlocalPaymentLogDatos(id uint, payerEmail string, monto float64) error { updates := map[string]interface{}{} if payerEmail != "" { updates["payer_email"] = payerEmail } if monto > 0 { updates["monto"] = monto } if len(updates) == 0 { return nil } return app.Http.Database.DB.Model(&DlocalPaymentLog{}).Where("id = ?", id).Updates(updates).Error } // GetDlocalPaymentLogsByRef devuelve todos los registros que coinciden con una referencia/order_id. func GetDlocalPaymentLogsByRef(ref string) ([]DlocalPaymentLog, error) { var logs []DlocalPaymentLog if err := app.Http.Database.DB. Where("referencia = ? OR order_id = ?", ref, ref). Order("id DESC"). Find(&logs).Error; err != nil { return nil, err } return logs, nil }