Skip to content

Commit

Permalink
Add task to keep checking if there were new MercadoPago payments that…
Browse files Browse the repository at this point in the history
… the system may have failed to receive via webhooks
  • Loading branch information
MrPowerGamerBR committed Apr 24, 2024
1 parent c8d9acc commit ef4bf37
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class PerfectPayments(

if (config.gateways.contains(PaymentGateway.MERCADOPAGO)) {
MercadoPagoConfig.setAccessToken(gateway.mercadoPago.accessToken) // Nasty!!
scheduleCoroutineAtFixedRate(UpdateMercadoPagoPaymentsTask::class.simpleName!!, tasksScope, 1.minutes, action = UpdateMercadoPagoPaymentsTask(this))
}

val server = embeddedServer(Netty, host = config.website.host, port = config.website.port) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import mu.KotlinLogging
import net.perfectdreams.perfectpayments.backend.PerfectPayments
import net.perfectdreams.perfectpayments.backend.dao.Payment
import net.perfectdreams.perfectpayments.backend.payments.PaymentStatus
import net.perfectdreams.perfectpayments.backend.utils.MercadoPagoUtils
import net.perfectdreams.perfectpayments.backend.utils.PaymentUtils
import net.perfectdreams.perfectpayments.backend.utils.extensions.respondEmptyJson
import net.perfectdreams.sequins.ktor.BaseRoute
Expand Down Expand Up @@ -81,28 +82,13 @@ class PostMercadoPagoCallbackRoute(val m: PerfectPayments) : BaseRoute("/api/v1/
return
}

when (payment.status) {
"approved" -> {
PaymentUtils.updatePaymentStatus(
m,
internalPayment,
PaymentStatus.APPROVED
)
}
"in_mediation" -> {
PaymentUtils.updatePaymentStatus(
m,
internalPayment,
PaymentStatus.CHARGED_BACK
)
}
"charged_back" -> {
PaymentUtils.updatePaymentStatus(
m,
internalPayment,
PaymentStatus.CHARGED_BACK
)
}
val paymentStatus = MercadoPagoUtils.getPaymentStatusFromMercadoPagoPaymentStatus(payment.status)
if (paymentStatus != null) {
PaymentUtils.updatePaymentStatus(
m,
internalPayment,
paymentStatus
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.perfectdreams.perfectpayments.backend.utils

import net.perfectdreams.perfectpayments.backend.payments.PaymentStatus

object MercadoPagoUtils {
fun getPaymentStatusFromMercadoPagoPaymentStatus(status: String): PaymentStatus? {
return when (status) {
"approved" -> PaymentStatus.APPROVED
"in_mediation" -> PaymentStatus.CHARGED_BACK
"charged_back" -> PaymentStatus.CHARGED_BACK
else -> null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package net.perfectdreams.perfectpayments.backend.utils

import com.mercadopago.client.payment.PaymentClient
import com.mercadopago.net.MPSearchRequest
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import mu.KotlinLogging
import net.perfectdreams.perfectpayments.backend.PerfectPayments
import net.perfectdreams.perfectpayments.backend.dao.Payment
import net.perfectdreams.perfectpayments.backend.routes.api.v1.callbacks.PostPagSeguroCallbackRoute
import net.perfectdreams.perfectpayments.backend.utils.extensions.respondEmptyJson
import org.jsoup.Jsoup
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter

/**
* Queries MercadoPago payments and updates their status if the payment is approved
*
* While not really needed, this is only as a fallback because "what if the webhooks fail"...
*/
class UpdateMercadoPagoPaymentsTask(val m: PerfectPayments) : RunnableCoroutine {
companion object {
private val logger = KotlinLogging.logger {}
}

private val paymentClient = PaymentClient()

override suspend fun run() {
logger.info { "Querying MercadoPago payments manually..." }

// This is so weird because the API that this SDK calls does not match the API reference
val result = paymentClient.search(
MPSearchRequest.builder()
.offset(0)
.limit(1000)
.filters(mapOf())
.build()
)

result.results.forEach {
val status = it.status
val reference = it.externalReference

// This code is from PostMercadoPagoCallbackRoute
logger.info { "MercadoPago payment $reference status is $status" }

val internalTransactionId = reference.split("-").last()

val internalPayment = m.newSuspendedTransaction {
Payment.findById(internalTransactionId.toLong())
}

if (internalPayment == null) {
logger.warn { "MercadoPago Payment with Reference ID: $reference ($internalTransactionId) doesn't have a matching internal ID! Bug?" }
return
}

val paymentStatus = MercadoPagoUtils.getPaymentStatusFromMercadoPagoPaymentStatus(status)

logger.info { "MercadoPago payment $reference status is $paymentStatus" }

if (paymentStatus != null) {
PaymentUtils.updatePaymentStatus(
m,
internalPayment,
paymentStatus
)
}
}
}
}

0 comments on commit ef4bf37

Please sign in to comment.