From ddbabea23f45c6605cc5baf01a30365bcdeb8614 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Fri, 1 May 2026 17:37:10 -0500 Subject: [PATCH] up --- pkg/models/dlocal_api.go | 12 +++ rest/controllers/api/pago_controller.go | 99 +++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/pkg/models/dlocal_api.go b/pkg/models/dlocal_api.go index f32aaa2..2aa02ff 100644 --- a/pkg/models/dlocal_api.go +++ b/pkg/models/dlocal_api.go @@ -149,3 +149,15 @@ func GetDlocalPaymentLogs(limit int) ([]DlocalPaymentLog, error) { } return logs, nil } + +// 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 +} diff --git a/rest/controllers/api/pago_controller.go b/rest/controllers/api/pago_controller.go index b446fda..e120ecc 100644 --- a/rest/controllers/api/pago_controller.go +++ b/rest/controllers/api/pago_controller.go @@ -2,9 +2,11 @@ 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. @@ -16,6 +18,12 @@ func PagoExitosoPage(c *fiber.Ctx) error { // 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 == "" { @@ -27,14 +35,93 @@ func PagoEstadoAPI(c *fiber.Ctx) error { return c.JSON(fiber.Map{"confirmado": false, "error": "ref inválido"}) } - confirmado, fechaPago, err := models.GetEstadoPago(contratoID) + // ─── 1. Consultar DB ────────────────────────────────────────────────────── + contrato, err := models.GetContratoParaVerificacion(contratoID) if err != nil { return c.JSON(fiber.Map{"confirmado": false, "error": "contrato no encontrado"}) } - - resp := fiber.Map{"confirmado": confirmado} - if confirmado && fechaPago != nil { - resp["fecha_pago"] = fechaPago.Format("02/01/2006 15:04") + 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) } - 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}) }