From 9c887524fe6c72c9402d1a3cfc1cdccf99e1988f Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 19 May 2025 11:50:52 +0300 Subject: [PATCH] Update returned payment handling: - when admin resets return payment, make sure datePaid is set to null - do not handle processed events after payment was marked as "Returned" - add errors to failed payments --- src/api/admin/admin.service.ts | 9 ++++++--- .../webhooks/trolley/handlers/payment.handler.ts | 7 ++++++- src/api/webhooks/trolley/handlers/payment.types.ts | 2 ++ src/shared/payments/payments.service.ts | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/api/admin/admin.service.ts b/src/api/admin/admin.service.ts index d1e6d18..3e6fdab 100644 --- a/src/api/admin/admin.service.ts +++ b/src/api/admin/admin.service.ts @@ -348,9 +348,12 @@ export class AdminService { currentVersion: number, ) { let setDatePaidNull = false; - if ( - (oldPaymentStatus === PaymentStatus.PAID || - oldPaymentStatus === PaymentStatus.PROCESSING) && + if ([ + PaymentStatus.PAID, + PaymentStatus.PROCESSING, + PaymentStatus.RETURNED, + PaymentStatus.FAILED, + ].includes(oldPaymentStatus as PaymentStatus) && newPaymentStatus === PaymentStatus.OWED ) { setDatePaidNull = true; diff --git a/src/api/webhooks/trolley/handlers/payment.handler.ts b/src/api/webhooks/trolley/handlers/payment.handler.ts index 521e9aa..96fe7b6 100644 --- a/src/api/webhooks/trolley/handlers/payment.handler.ts +++ b/src/api/webhooks/trolley/handlers/payment.handler.ts @@ -34,7 +34,11 @@ export class PaymentHandler { paymentId, payload.status.toUpperCase() as payment_status, payload.status.toUpperCase(), - { failureMessage: payload.failureMessage }, + { + failureMessage: payload.failureMessage, + returnedNote: payload.returnedNote, + errors: payload.errors?.join(', '), + }, ); return; @@ -56,6 +60,7 @@ export class PaymentHandler { INNER JOIN public.payment_release_associations pra ON pra.payment_id = p.payment_id WHERE pra.payment_release_id::text = ${paymentId} + FOR UPDATE ` ).map((w) => w.id); diff --git a/src/api/webhooks/trolley/handlers/payment.types.ts b/src/api/webhooks/trolley/handlers/payment.types.ts index 06eddef..9168bae 100644 --- a/src/api/webhooks/trolley/handlers/payment.types.ts +++ b/src/api/webhooks/trolley/handlers/payment.types.ts @@ -23,6 +23,8 @@ export interface PaymentProcessedEventData { fees: string; targetAmount: string; // net amount failureMessage: string | null; + errors?: string[]; + returnedNote?: string; memo: string | null; batch: { id: string; diff --git a/src/shared/payments/payments.service.ts b/src/shared/payments/payments.service.ts index 9a2da5e..b7aa4a4 100644 --- a/src/shared/payments/payments.service.ts +++ b/src/shared/payments/payments.service.ts @@ -138,6 +138,20 @@ export class PaymentsService { metadata?: JsonObject, ) { const prismaClient = transaction || this.prisma; + + const failedOrReturnedRelease = await prismaClient.payment_releases.findFirst({ + where: { + payment_release_id: paymentId, + status: { in: [payment_status.RETURNED, payment_status.FAILED] }, + } + }); + + if (failedOrReturnedRelease) { + throw new Error( + `Not processing payment release ${paymentId} because it was already marked as '${failedOrReturnedRelease.status}'.`, + ); + } + try { const r = await prismaClient.payment_releases.updateMany({ where: {