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}) }