up
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
)
|
||||
|
||||
// PasarelasPage renderiza la vista unificada de pasarelas de pago.
|
||||
@@ -173,7 +176,7 @@ func BoldCallbackLogs(c *fiber.Ctx) error {
|
||||
|
||||
// ─── Logs dLocal ──────────────────────────────────────────────────────────────
|
||||
|
||||
// DlocalPaymentLogs devuelve los últimos 100 registros de pagos de dLocal.
|
||||
// DlocalPaymentLogs devuelve los últimos 100 registros de pagos de dLocal (legacy).
|
||||
func DlocalPaymentLogs(c *fiber.Ctx) error {
|
||||
logs, err := models.GetDlocalPaymentLogs(100)
|
||||
if err != nil {
|
||||
@@ -181,3 +184,261 @@ func DlocalPaymentLogs(c *fiber.Ctx) error {
|
||||
}
|
||||
return c.JSON(fiber.Map{"data": logs})
|
||||
}
|
||||
|
||||
// DlocalPaymentLogsPaginated devuelve los logs con paginación y filtro por estado.
|
||||
// Query params: page (default 1), limit (default 25), estado (PAID|PENDING|REJECTED|APROBADOS|TODOS)
|
||||
func DlocalPaymentLogsPaginated(c *fiber.Ctx) error {
|
||||
page := c.QueryInt("page", 1)
|
||||
limit := c.QueryInt("limit", 25)
|
||||
estado := c.Query("estado", "")
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
logs, total, err := models.GetDlocalPaymentLogsPaginated(page, limit, estado)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"data": logs,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
})
|
||||
}
|
||||
|
||||
// ValidarDlocalLog verifica el estado de pago real de un log dLocal consultando
|
||||
// todas las fuentes disponibles (dlocal_payment_log → Bold API → dLocal API).
|
||||
// Si se confirma el pago, marca el contrato como pagado y envía confirmación.
|
||||
// POST /app/pasarelas/dlocal/logs/:id/validar
|
||||
func ValidarDlocalLog(c *fiber.Ctx) error {
|
||||
logID, err := c.ParamsInt("id")
|
||||
if err != nil || logID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
|
||||
var entry models.DlocalPaymentLog
|
||||
if err := models.GetDlocalPaymentLogByID(uint(logID), &entry); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Log no encontrado"})
|
||||
}
|
||||
|
||||
ref := entry.Referencia
|
||||
if ref == "" {
|
||||
ref = entry.OrderID
|
||||
}
|
||||
|
||||
var contratoID uint
|
||||
if _, err := fmt.Sscanf(ref, "contrato-%d", &contratoID); err != nil || contratoID == 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Referencia no tiene formato contrato-{id}"})
|
||||
}
|
||||
|
||||
contrato, err := models.GetContratoParaVerificacion(contratoID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Contrato no encontrado"})
|
||||
}
|
||||
|
||||
payerEmail := entry.PayerEmail
|
||||
if payerEmail == "" {
|
||||
payerEmail = contrato.Cliente.Email
|
||||
}
|
||||
monto := entry.Monto
|
||||
pagoConfirmado := contrato.PagoConfirmado
|
||||
fuenteConfirmacion := ""
|
||||
|
||||
// ─── 1. Ya confirmado en DB ───────────────────────────────────────────────
|
||||
if pagoConfirmado {
|
||||
fuenteConfirmacion = "db"
|
||||
}
|
||||
|
||||
// ─── 2. Mismo log si ya tiene estado PAID ────────────────────────────────
|
||||
if !pagoConfirmado && (entry.Estado == "PAID" || entry.Estado == "AUTHORIZED") {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "dlocal_log"
|
||||
}
|
||||
|
||||
// ─── 3. Bold API ─────────────────────────────────────────────────────────
|
||||
if !pagoConfirmado && contrato.EnlacePagoLinkID != "" {
|
||||
boldCfg, boldErr := models.GetBoldConfig()
|
||||
if boldErr == nil {
|
||||
paid, _, apiMonto, apiErr := services.CheckBoldLinkPaid(boldCfg, contrato.EnlacePagoLinkID)
|
||||
if apiErr == nil && paid {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "bold_api"
|
||||
if apiMonto > 0 {
|
||||
monto = float64(apiMonto)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 4. dLocal API ───────────────────────────────────────────────────────
|
||||
if !pagoConfirmado {
|
||||
dlocalCfg, dlErr := models.GetLastActiveDlocalApi()
|
||||
if dlErr == nil {
|
||||
paid, _, apiMonto, apiEmail, apiErr := services.CheckDlocalPaymentByOrderID(*dlocalCfg, ref)
|
||||
if apiErr == nil && paid {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "dlocal_api"
|
||||
if apiMonto > 0 {
|
||||
monto = apiMonto
|
||||
}
|
||||
if apiEmail != "" {
|
||||
payerEmail = apiEmail
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si el pago se confirmó ahora (no estaba marcado antes), actualizar contrato
|
||||
if pagoConfirmado && !contrato.PagoConfirmado {
|
||||
_ = models.MarcarContratoPagado(contratoID)
|
||||
go services.EnviarCorreoConfirmacionPago(contratoID)
|
||||
}
|
||||
|
||||
_ = models.UpdateDlocalPaymentLogDatos(uint(logID), payerEmail, monto)
|
||||
_ = models.GetDlocalPaymentLogByID(uint(logID), &entry)
|
||||
|
||||
msg := "Datos actualizados"
|
||||
if pagoConfirmado && !contrato.PagoConfirmado {
|
||||
msg = fmt.Sprintf("Pago confirmado via %s — contrato marcado como pagado", fuenteConfirmacion)
|
||||
} else if pagoConfirmado {
|
||||
msg = fmt.Sprintf("Pago ya confirmado (%s)", fuenteConfirmacion)
|
||||
} else {
|
||||
msg = "Pago aún no confirmado — datos actualizados"
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"ok": true,
|
||||
"confirmado": pagoConfirmado,
|
||||
"fuente": fuenteConfirmacion,
|
||||
"mensaje": msg,
|
||||
"data": entry,
|
||||
})
|
||||
}
|
||||
|
||||
// ─── Validación de log API_CHECK ─────────────────────────────────────────────
|
||||
|
||||
// ValidarBoldLog verifica el estado de pago real de un log API_CHECK consultando
|
||||
// todas las fuentes disponibles (dlocal_payment_log → Bold API → dLocal API).
|
||||
// Si se confirma el pago, marca el contrato como pagado y envía el email de confirmación.
|
||||
// También rellena email y monto faltantes. Funciona para cualquier tipo de log Bold.
|
||||
// POST /app/pasarelas/bold/logs/:id/validar
|
||||
func ValidarBoldLog(c *fiber.Ctx) error {
|
||||
logID, err := c.ParamsInt("id")
|
||||
if err != nil || logID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
|
||||
// Cargar el registro existente
|
||||
var entry models.BoldWebhookLog
|
||||
if err := models.GetBoldWebhookLogByID(uint(logID), &entry); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Log no encontrado"})
|
||||
}
|
||||
|
||||
// Parsear contrato ID de la referencia (contrato-{id})
|
||||
var contratoID uint
|
||||
if _, err := fmt.Sscanf(entry.Referencia, "contrato-%d", &contratoID); err != nil || contratoID == 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Referencia no tiene formato contrato-{id}"})
|
||||
}
|
||||
|
||||
// Cargar contrato con cliente
|
||||
contrato, err := models.GetContratoParaVerificacion(contratoID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Contrato no encontrado"})
|
||||
}
|
||||
|
||||
// Valores iniciales: reutilizar lo que ya hay en el log, fallback al cliente
|
||||
payerEmail := entry.PayerEmail
|
||||
if payerEmail == "" {
|
||||
payerEmail = contrato.Cliente.Email
|
||||
}
|
||||
monto := entry.Monto
|
||||
pagoConfirmado := contrato.PagoConfirmado
|
||||
fuenteConfirmacion := ""
|
||||
|
||||
// ─── 1. Ya confirmado en DB ───────────────────────────────────────────────
|
||||
if pagoConfirmado {
|
||||
fuenteConfirmacion = "db"
|
||||
}
|
||||
|
||||
// ─── 2. dlocal_payment_log ────────────────────────────────────────────────
|
||||
if !pagoConfirmado {
|
||||
dlocalLogs, dlErr := models.GetDlocalPaymentLogsByRef(entry.Referencia)
|
||||
if dlErr == nil {
|
||||
for _, l := range dlocalLogs {
|
||||
if l.Estado == "PAID" || l.Estado == "AUTHORIZED" {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "dlocal_log"
|
||||
if l.PayerEmail != "" {
|
||||
payerEmail = l.PayerEmail
|
||||
}
|
||||
if l.Monto > 0 {
|
||||
monto = int64(l.Monto)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 3. Bold API ─────────────────────────────────────────────────────────
|
||||
if !pagoConfirmado && contrato.EnlacePagoLinkID != "" {
|
||||
boldCfg, boldErr := models.GetBoldConfig()
|
||||
if boldErr == nil {
|
||||
paid, _, apiMonto, apiErr := services.CheckBoldLinkPaid(boldCfg, contrato.EnlacePagoLinkID)
|
||||
if apiErr == nil && paid {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "bold_api"
|
||||
if apiMonto > 0 {
|
||||
monto = apiMonto
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 4. dLocal API ───────────────────────────────────────────────────────
|
||||
if !pagoConfirmado {
|
||||
dlocalCfg, dlErr := models.GetLastActiveDlocalApi()
|
||||
if dlErr == nil {
|
||||
paid, _, apiMonto, apiEmail, apiErr := services.CheckDlocalPaymentByOrderID(*dlocalCfg, entry.Referencia)
|
||||
if apiErr == nil && paid {
|
||||
pagoConfirmado = true
|
||||
fuenteConfirmacion = "dlocal_api"
|
||||
if apiMonto > 0 {
|
||||
monto = int64(apiMonto)
|
||||
}
|
||||
if apiEmail != "" {
|
||||
payerEmail = apiEmail
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si el pago se confirmó ahora (no estaba marcado antes), actualizar contrato
|
||||
if pagoConfirmado && !contrato.PagoConfirmado {
|
||||
_ = models.MarcarContratoPagado(contratoID)
|
||||
go services.EnviarCorreoConfirmacionPago(contratoID)
|
||||
}
|
||||
|
||||
// Actualizar log con los mejores datos disponibles
|
||||
_ = models.UpdateBoldWebhookLogDatos(uint(logID), payerEmail, monto)
|
||||
|
||||
// Devolver el log actualizado
|
||||
_ = models.GetBoldWebhookLogByID(uint(logID), &entry)
|
||||
|
||||
msg := "Datos actualizados"
|
||||
if pagoConfirmado && !contrato.PagoConfirmado {
|
||||
msg = fmt.Sprintf("Pago confirmado via %s — contrato marcado como pagado", fuenteConfirmacion)
|
||||
} else if pagoConfirmado {
|
||||
msg = fmt.Sprintf("Pago ya confirmado (%s)", fuenteConfirmacion)
|
||||
} else {
|
||||
msg = "Pago aún no confirmado — datos del contrato actualizados"
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"ok": true,
|
||||
"confirmado": pagoConfirmado,
|
||||
"fuente": fuenteConfirmacion,
|
||||
"mensaje": msg,
|
||||
"data": entry,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user