Files
soft_usite/rest/controllers/api/pago_controller.go
T
2026-05-01 17:37:10 -05:00

128 lines
4.9 KiB
Go

package controllers
import (
"fmt"
"log"
"github.com/gofiber/fiber/v2"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
)
// PagoExitosoPage renderiza la página pública de confirmación de pago.
// Bold redirige al cliente aquí tras el pago. La URL puede incluir ?ref=contrato-{id}.
func PagoExitosoPage(c *fiber.Ctx) error {
ref := c.Query("ref", "")
return c.Render("pago_exitoso", fiber.Map{"Ref": ref}, "layouts/landing")
}
// PagoEstadoAPI devuelve el estado de pago de un contrato para polling desde el frontend.
// GET /api/pago-estado?ref=contrato-{id}
//
// Flujo de verificación (en orden):
// 1. Lee pago_confirmado de la DB → si ya confirmado, retorna ok.
// 2. Si no confirmado, revisa dlocal_payment_log buscando ref con estado PAID.
// 3. Si aún no confirmado, consulta Bold API directamente usando enlace_pago_link_id.
// 4. Si la pasarela confirma el pago, marca el contrato y retorna confirmado.
func PagoEstadoAPI(c *fiber.Ctx) error {
ref := c.Query("ref", "")
if ref == "" {
return c.JSON(fiber.Map{"confirmado": false, "error": "ref requerido"})
}
var contratoID uint
if _, err := fmt.Sscanf(ref, "contrato-%d", &contratoID); err != nil || contratoID == 0 {
return c.JSON(fiber.Map{"confirmado": false, "error": "ref inválido"})
}
// ─── 1. Consultar DB ──────────────────────────────────────────────────────
contrato, err := models.GetContratoParaVerificacion(contratoID)
if err != nil {
return c.JSON(fiber.Map{"confirmado": false, "error": "contrato no encontrado"})
}
if contrato.PagoConfirmado {
resp := fiber.Map{"confirmado": true, "fuente": "db"}
if contrato.FechaPago != nil {
resp["fecha_pago"] = contrato.FechaPago.Format("02/01/2006 15:04")
}
return c.JSON(resp)
}
// ─── 2. Revisar log de dLocal (puede haber llegado antes que el webhook) ──
dlocalLogs, err := models.GetDlocalPaymentLogsByRef(ref)
if err == nil {
for _, l := range dlocalLogs {
if l.Estado == "PAID" || l.Estado == "AUTHORIZED" {
log.Printf("[PAGO-ESTADO] Contrato %d confirmado via dlocal_payment_log (id=%d)", contratoID, l.ID)
_ = models.MarcarContratoPagado(contratoID)
now := l.CreatedAt
return c.JSON(fiber.Map{
"confirmado": true,
"fuente": "dlocal_log",
"fecha_pago": now.Format("02/01/2006 15:04"),
})
}
}
}
// ─── 3. Consultar Bold API directamente si hay link_id almacenado ─────────
if contrato.EnlacePagoLinkID != "" {
boldCfg, boldErr := models.GetBoldConfig()
if boldErr == nil {
paid, paymentID, boldApiErr := services.CheckBoldLinkPaid(boldCfg, contrato.EnlacePagoLinkID)
if boldApiErr != nil {
log.Printf("[PAGO-ESTADO] Bold API error para link %s: %v", contrato.EnlacePagoLinkID, boldApiErr)
} else if paid {
log.Printf("[PAGO-ESTADO] Contrato %d confirmado via Bold API (payment_id=%s)", contratoID, paymentID)
_ = models.MarcarContratoPagado(contratoID)
// Guardar en bold_webhook_log como registro de esta verificación activa
if paymentID != "" && !models.IsBoldNotificationDuplicate("api-check-"+paymentID) {
_ = models.SaveBoldWebhookLog(models.BoldWebhookLog{
NotificationID: "api-check-" + paymentID,
Tipo: "API_CHECK",
PaymentID: paymentID,
Referencia: ref,
Procesado: true,
})
}
return c.JSON(fiber.Map{
"confirmado": true,
"fuente": "bold_api",
})
}
}
}
// ─── 4. Consultar dLocal API directamente por order_id ────────────────────
dlocalCfg, dlocalErr := models.GetLastActiveDlocalApi()
if dlocalErr == nil {
paid, paymentID, dlocalApiErr := services.CheckDlocalPaymentByOrderID(*dlocalCfg, ref)
if dlocalApiErr != nil {
log.Printf("[PAGO-ESTADO] dLocal API error para order_id %s: %v", ref, dlocalApiErr)
} else if paid {
log.Printf("[PAGO-ESTADO] Contrato %d confirmado via dLocal API (payment_id=%s)", contratoID, paymentID)
_ = models.MarcarContratoPagado(contratoID)
// Guardar en dlocal_payment_log como registro de esta verificación activa
notifID := "api-check-" + ref
if !models.IsDlocalNotificationDuplicate(notifID) {
_ = models.SaveDlocalPaymentLog(models.DlocalPaymentLog{
NotificationID: notifID,
Fuente: "api_check",
Tipo: "API_CHECK",
Estado: "PAID",
PaymentID: paymentID,
Referencia: ref,
Procesado: true,
})
}
return c.JSON(fiber.Map{
"confirmado": true,
"fuente": "dlocal_api",
})
}
}
// ─── Sin confirmación aún ─────────────────────────────────────────────────
return c.JSON(fiber.Map{"confirmado": false})
}