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: {