diff --git a/pkg/models/notificacion_regla.go b/pkg/models/notificacion_regla.go
index 1d650e6..c6b5e71 100644
--- a/pkg/models/notificacion_regla.go
+++ b/pkg/models/notificacion_regla.go
@@ -7,12 +7,13 @@ import (
type NotificacionRegla struct {
gorm.Model
- Nombre string `json:"nombre" gorm:"column:nombre"`
- DiasAntes int `json:"dias_antes" gorm:"column:dias_antes"`
- PlantillaID uint `json:"plantilla_id" gorm:"column:plantilla_id"`
- Plantilla PlantillaCorreo `json:"plantilla" gorm:"foreignKey:PlantillaID"`
- Activo bool `json:"activo" gorm:"column:activo;default:true"`
- AplicaA string `json:"aplica_a" gorm:"column:aplica_a;default:'todos'"` // todos | renovable | unico
+ Nombre string `json:"nombre" gorm:"column:nombre"`
+ DiasAntes int `json:"dias_antes" gorm:"column:dias_antes"`
+ PlantillaID uint `json:"plantilla_id" gorm:"column:plantilla_id"`
+ Plantilla PlantillaCorreo `json:"plantilla" gorm:"foreignKey:PlantillaID"`
+ Activo bool `json:"activo" gorm:"column:activo;default:true"`
+ AplicaA string `json:"aplica_a" gorm:"column:aplica_a;default:'todos'"` // todos | renovable | unico
+ PasarelaEnlace string `json:"pasarela_enlace" gorm:"column:pasarela_enlace;default:'bold'"` // bold | dlocal | ninguna
}
func (NotificacionRegla) TableName() string { return "notificacion_reglas" }
@@ -48,11 +49,12 @@ func CreateRegla(r NotificacionRegla) error {
func UpdateRegla(r NotificacionRegla) error {
return app.Http.Database.DB.Model(&r).Updates(map[string]interface{}{
- "nombre": r.Nombre,
- "dias_antes": r.DiasAntes,
- "plantilla_id": r.PlantillaID,
- "activo": r.Activo,
- "aplica_a": r.AplicaA,
+ "nombre": r.Nombre,
+ "dias_antes": r.DiasAntes,
+ "plantilla_id": r.PlantillaID,
+ "activo": r.Activo,
+ "aplica_a": r.AplicaA,
+ "pasarela_enlace": r.PasarelaEnlace,
}).Error
}
diff --git a/pkg/services/renovacion_service.go b/pkg/services/renovacion_service.go
index f461cf3..aed1681 100644
--- a/pkg/services/renovacion_service.go
+++ b/pkg/services/renovacion_service.go
@@ -142,7 +142,7 @@ func EnviarNotificacionGrupo(regla *models.NotificacionRegla, cliente *models.Cl
// Generar o reutilizar el enlace de pago para el primer contrato del grupo
enlacePago := ""
if len(contratos) > 0 {
- enlacePago = ObtenerOCrearEnlacePago(&contratos[0])
+ enlacePago = ObtenerOCrearEnlacePago(&contratos[0], regla.PasarelaEnlace)
}
datos := DatosPlantilla{
@@ -221,24 +221,40 @@ func ReenviarLog(logEntry *models.NotificacionLog) error {
return sendErr
}
-// ObtenerOCrearEnlacePago devuelve el enlace Bold vigente del contrato.
-// Si ya existe uno (no ha sido pagado aún), lo reutiliza.
-// Si no existe, crea uno nuevo en Bold y lo guarda en el contrato.
-// Cuando Bold notifica SALE_APPROVED, llamar models.LimpiarEnlacePago(contratoID)
-// para que la próxima notificación genere un link nuevo.
-func ObtenerOCrearEnlacePago(contrato *models.Contrato) string {
+// ObtenerOCrearEnlacePago devuelve el enlace de pago vigente del contrato.
+// gateway puede ser "bold", "dlocal" o "ninguna"/"".
+// Si ya existe un enlace guardado, lo reutiliza (mismo ciclo).
+// Cuando el pago se aprueba, llamar models.LimpiarEnlacePago para el siguiente ciclo.
+func ObtenerOCrearEnlacePago(contrato *models.Contrato, gateway string) string {
+ // Normalizar gateway vacío → bold por defecto
+ if gateway == "" {
+ gateway = "bold"
+ }
+ if gateway == "ninguna" {
+ return ""
+ }
+
// Reutilizar si ya hay uno vigente
if contrato.EnlacePago != "" {
return contrato.EnlacePago
}
+ switch gateway {
+ case "dlocal":
+ return obtenerEnlaceDlocal(contrato)
+ default: // "bold"
+ return obtenerEnlaceBold(contrato)
+ }
+}
+
+// obtenerEnlaceBold crea un payment link en Bold y lo persiste en el contrato.
+func obtenerEnlaceBold(contrato *models.Contrato) string {
cfg, err := models.GetBoldConfig()
if err != nil {
- log.Printf("[BOLD] ObtenerOCrearEnlacePago: sin config activa para contrato %d", contrato.ID)
+ log.Printf("[BOLD] sin config activa para contrato %d", contrato.ID)
return ""
}
- // Nombre de servicios en la descripción
desc := fmt.Sprintf("Renovación contrato #%d", contrato.ID)
if len(contrato.Servicios) > 0 {
desc = fmt.Sprintf("Renovación: %s", contrato.Servicios[0].Nombre)
@@ -257,13 +273,55 @@ func ObtenerOCrearEnlacePago(contrato *models.Contrato) string {
result, err := CreateBoldPaymentLink(cfg, req)
if err != nil {
- log.Printf("[BOLD] ObtenerOCrearEnlacePago: error creando link para contrato %d: %v", contrato.ID, err)
+ log.Printf("[BOLD] error creando link para contrato %d: %v", contrato.ID, err)
return ""
}
- // Persistir en BD
_ = models.GuardarEnlacePago(contrato.ID, result.Payload.PaymentLink, result.Payload.URL)
contrato.EnlacePago = result.Payload.URL
contrato.EnlacePagoLinkID = result.Payload.PaymentLink
return result.Payload.URL
}
+
+// obtenerEnlaceDlocal crea un pago en dLocal y devuelve la URL de redirección.
+func obtenerEnlaceDlocal(contrato *models.Contrato) string {
+ cfg, err := models.GetLastActiveDlocalApi()
+ if err != nil {
+ log.Printf("[DLOCAL] sin config activa para contrato %d", contrato.ID)
+ return ""
+ }
+
+ desc := fmt.Sprintf("Renovación contrato #%d", contrato.ID)
+ if len(contrato.Servicios) > 0 {
+ desc = fmt.Sprintf("Renovación: %s", contrato.Servicios[0].Nombre)
+ }
+
+ pagoReq := PagoRequest{
+ Currency: "COP",
+ Amount: contrato.PrecioAcordado,
+ OrderID: int(contrato.ID),
+ Description: desc,
+ SuccessURL: cfg.UrlProd + "/pago-exitoso",
+ BackURL: cfg.UrlProd + "/pago-cancelado",
+ }
+
+ body, err := CreatePago(*cfg, pagoReq)
+ if err != nil {
+ log.Printf("[DLOCAL] error creando pago para contrato %d: %v", contrato.ID, err)
+ return ""
+ }
+
+ var resp struct {
+ RedirectURL string `json:"redirect_url"`
+ ID string `json:"id"`
+ }
+ if err := json.Unmarshal(body, &resp); err != nil || resp.RedirectURL == "" {
+ log.Printf("[DLOCAL] respuesta sin redirect_url para contrato %d: %s", contrato.ID, string(body))
+ return ""
+ }
+
+ _ = models.GuardarEnlacePago(contrato.ID, resp.ID, resp.RedirectURL)
+ contrato.EnlacePago = resp.RedirectURL
+ contrato.EnlacePagoLinkID = resp.ID
+ return resp.RedirectURL
+}
diff --git a/resources/views/renovaciones/plantillas.html b/resources/views/renovaciones/plantillas.html
index c7bf830..7024b43 100644
--- a/resources/views/renovaciones/plantillas.html
+++ b/resources/views/renovaciones/plantillas.html
@@ -82,7 +82,9 @@
{{.FechaVencimiento}},
{{.DiasRestantes}},
{{.Total}},
- {{range .Servicios}}...{{.Nombre}} {{.Precio}}...{{end}}
+ {{range .Servicios}}...{{.Nombre}} {{.Precio}}...{{end}},
+ {{.EnlacePago}}
+ (URL de pago generada automáticamente por Bold o dLocal al enviar)