@@ -3,7 +3,7 @@ import { ENV_CONFIG } from 'src/config';
3
3
import { PrismaService } from 'src/shared/global/prisma.service' ;
4
4
import { TaxFormRepository } from '../repository/taxForm.repo' ;
5
5
import { PaymentMethodRepository } from '../repository/paymentMethod.repo' ;
6
- import { payment_releases , payment_status , PrismaClient } from '@prisma/client' ;
6
+ import { payment_releases , payment_status , Prisma } from '@prisma/client' ;
7
7
import { TrolleyService } from 'src/shared/global/trolley.service' ;
8
8
import { PaymentsService } from 'src/shared/payments' ;
9
9
@@ -42,12 +42,14 @@ export class WithdrawalService {
42
42
private async getReleasableWinningsForUserId (
43
43
userId : string ,
44
44
winningsIds : string [ ] ,
45
+ tx : Prisma . TransactionClient ,
45
46
) {
46
- const winnings = await this . prisma . $queryRaw < ReleasableWinningRow [ ] > `
47
+ const winnings = await tx . $queryRaw < ReleasableWinningRow [ ] > `
47
48
SELECT p.payment_id as "paymentId", p.total_amount as amount, p.version, w.title, w.external_id as "externalId", p.payment_status as status, p.release_date as "releaseDate", p.date_paid as "datePaid"
48
49
FROM payment p INNER JOIN winnings w on p.winnings_id = w.winning_id
49
50
AND p.installment_number = 1
50
51
WHERE p.winnings_id = ANY(${ winningsIds } ::uuid[]) AND w.winner_id = ${ userId }
52
+ FOR UPDATE NOWAIT
51
53
` ;
52
54
53
55
if ( winnings . length < winningsIds . length ) {
@@ -91,7 +93,7 @@ export class WithdrawalService {
91
93
}
92
94
93
95
private async createDbPaymentRelease (
94
- tx : PrismaClient ,
96
+ tx : Prisma . TransactionClient ,
95
97
userId : string ,
96
98
totalAmount : number ,
97
99
paymentMethodId : number ,
@@ -129,7 +131,7 @@ export class WithdrawalService {
129
131
}
130
132
131
133
private async updateDbReleaseRecord (
132
- tx : PrismaClient ,
134
+ tx : Prisma . TransactionClient ,
133
135
paymentRelease : payment_releases ,
134
136
externalTxId : string ,
135
137
) {
@@ -168,67 +170,80 @@ export class WithdrawalService {
168
170
) ;
169
171
}
170
172
171
- const winnings = await this . getReleasableWinningsForUserId (
172
- userId ,
173
- winningsIds ,
174
- ) ;
175
-
176
- const totalAmount = this . checkTotalAmount ( winnings ) ;
173
+ try {
174
+ await this . prisma . $transaction ( async ( tx ) => {
175
+ const winnings = await this . getReleasableWinningsForUserId (
176
+ userId ,
177
+ winningsIds ,
178
+ tx ,
179
+ ) ;
177
180
178
- this . logger . log ( 'Begin processing payments' , winnings ) ;
179
- await this . prisma . $transaction ( async ( tx ) => {
180
- const recipient = await this . getTrolleyRecipientByUserId ( userId ) ;
181
+ const totalAmount = this . checkTotalAmount ( winnings ) ;
181
182
182
- if ( ! recipient ) {
183
- throw new Error ( `Trolley recipient not found for user '${ userId } '!` ) ;
184
- }
183
+ this . logger . log ( 'Begin processing payments' , winnings ) ;
185
184
186
- const paymentRelease = await this . createDbPaymentRelease (
187
- tx as PrismaClient ,
188
- userId ,
189
- totalAmount ,
190
- connectedPaymentMethod . payment_method_id ,
191
- recipient . trolley_id ,
192
- winnings ,
193
- ) ;
185
+ const recipient = await this . getTrolleyRecipientByUserId ( userId ) ;
194
186
195
- const paymentBatch = await this . trolleyService . startBatchPayment (
196
- ` ${ userId } _ ${ userHandle } ` ,
197
- ) ;
187
+ if ( ! recipient ) {
188
+ throw new Error ( `Trolley recipient not found for user ' ${ userId } '!` ) ;
189
+ }
198
190
199
- const trolleyPayment = await this . trolleyService . createPayment (
200
- recipient . trolley_id ,
201
- paymentBatch . id ,
202
- totalAmount ,
203
- paymentRelease . payment_release_id ,
204
- ) ;
191
+ const paymentRelease = await this . createDbPaymentRelease (
192
+ tx ,
193
+ userId ,
194
+ totalAmount ,
195
+ connectedPaymentMethod . payment_method_id ,
196
+ recipient . trolley_id ,
197
+ winnings ,
198
+ ) ;
205
199
206
- await this . updateDbReleaseRecord (
207
- tx as PrismaClient ,
208
- paymentRelease ,
209
- trolleyPayment . id ,
210
- ) ;
200
+ const paymentBatch = await this . trolleyService . startBatchPayment (
201
+ `${ userId } _${ userHandle } ` ,
202
+ ) ;
211
203
212
- try {
213
- await this . paymentsService . updatePaymentProcessingState (
214
- winningsIds ,
215
- payment_status . PROCESSING ,
216
- tx ,
204
+ const trolleyPayment = await this . trolleyService . createPayment (
205
+ recipient . trolley_id ,
206
+ paymentBatch . id ,
207
+ totalAmount ,
208
+ paymentRelease . payment_release_id ,
217
209
) ;
218
- } catch ( e ) {
210
+
211
+ await this . updateDbReleaseRecord ( tx , paymentRelease , trolleyPayment . id ) ;
212
+
213
+ try {
214
+ await this . paymentsService . updatePaymentProcessingState (
215
+ winningsIds ,
216
+ payment_status . PROCESSING ,
217
+ tx ,
218
+ ) ;
219
+ } catch ( e ) {
220
+ this . logger . error (
221
+ `Failed to update payment processing state: ${ e . message } for winnings '${ winningsIds . join ( ',' ) } ` ,
222
+ ) ;
223
+ throw new Error ( 'Failed to update payment processing state!' ) ;
224
+ }
225
+
226
+ try {
227
+ await this . trolleyService . startProcessingPayment ( paymentBatch . id ) ;
228
+ } catch ( error ) {
229
+ const errorMsg = `Failed to release payment: ${ error . message } ` ;
230
+ this . logger . error ( errorMsg , error ) ;
231
+ throw new Error ( errorMsg ) ;
232
+ }
233
+ } ) ;
234
+ } catch ( error ) {
235
+ if ( error . code === 'P2010' && error . meta ?. code === '55P03' ) {
219
236
this . logger . error (
220
- `Failed to update payment processing state: ${ e . message } for winnings '${ winningsIds . join ( ',' ) } ` ,
237
+ 'Payment request denied because payment row was locked previously!' ,
238
+ error ,
221
239
) ;
222
- throw new Error ( 'Failed to update payment processing state!' ) ;
223
- }
224
240
225
- try {
226
- await this . trolleyService . startProcessingPayment ( paymentBatch . id ) ;
227
- } catch ( error ) {
228
- const errorMsg = `Failed to release payment: ${ error . message } ` ;
229
- this . logger . error ( errorMsg , error ) ;
230
- throw new Error ( errorMsg ) ;
241
+ throw new Error (
242
+ 'Some or all of the winnings you requested to process are either processing, on hold or already paid.' ,
243
+ ) ;
244
+ } else {
245
+ throw error ;
231
246
}
232
- } ) ;
247
+ }
233
248
}
234
249
}
0 commit comments