feat: selector de pasarela (Bold/dLocal/ninguna) en regla + muestra {{.EnlacePago}} en editor de plantillas

This commit is contained in:
Lizandro Guarnizo
2026-05-01 12:47:13 -05:00
parent 8c4b401379
commit 0da9331a5e
4 changed files with 103 additions and 26 deletions
+69 -11
View File
@@ -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
}