@@ -13,6 +13,17 @@ const client = trolley({
13
13
secret : TROLLEY_SECRET_KEY ,
14
14
} ) ;
15
15
16
+ /**
17
+ * Determines if the provided validation errors indicate an "insufficient funds" error.
18
+ */
19
+ const isInsufficientFundsError = ( {
20
+ validationErrors,
21
+ } : {
22
+ validationErrors : { code : string } [ ] ;
23
+ } ) =>
24
+ validationErrors . length === 1 &&
25
+ validationErrors [ 0 ] . code === 'non_sufficient_funds' ;
26
+
16
27
@Injectable ( )
17
28
export class TrolleyService {
18
29
private readonly logger = new Logger ( `global/TrolleyService` ) ;
@@ -78,24 +89,63 @@ export class TrolleyService {
78
89
return ;
79
90
}
80
91
92
+ const paymentPayload = {
93
+ recipient : {
94
+ id : recipientId ,
95
+ } ,
96
+ sourceAmount : totalAmount . toString ( ) ,
97
+ sourceCurrency : 'USD' ,
98
+ memo : 'Topcoder payment' ,
99
+ // TODO: remove `,${Date.now()}`
100
+ // if externalId is present, it must be unique
101
+ externalId : `${ winningsIds . join ( ',' ) } ,${ Date . now ( ) } ` ,
102
+ } ;
103
+
81
104
try {
82
- const payment = await this . client . payment . create ( paymentBatch . id , {
83
- recipient : {
84
- id : recipientId ,
85
- } ,
86
- sourceAmount : totalAmount . toString ( ) ,
87
- sourceCurrency : 'USD' ,
88
- memo : 'Topcoder payment' ,
89
- // TODO: remove `,${Date.now()}`
90
- // if externalId is present, it must be unique
91
- externalId : `${ winningsIds . join ( ',' ) } ,${ Date . now ( ) } ` ,
92
- } ) ;
105
+ const payment = await this . client . payment . create (
106
+ paymentBatch . id ,
107
+ paymentPayload ,
108
+ ) ;
93
109
94
110
this . logger . debug ( `Created payment with id ${ payment . id } ` ) ;
95
111
96
112
return paymentBatch ;
97
113
} catch ( e ) {
98
- this . logger . error ( `Failed to create payment, error '${ e . message } '!` ) ;
114
+ this . logger . error (
115
+ `Failed to create payment, error '${ e . message } '!` ,
116
+ paymentPayload ,
117
+ e . validationErrors
118
+ ? { validationErrors : e . validationErrors }
119
+ : undefined ,
120
+ ) ;
121
+ }
122
+ }
123
+
124
+ async startProcessingPayment ( paymentBatchId : string ) {
125
+ try {
126
+ // generate quote
127
+ await this . client . batch . generateQuote ( paymentBatchId ) ;
128
+
129
+ // trigger trolley payment (batch) process
130
+ await this . client . batch . startProcessing ( paymentBatchId ) ;
131
+ } catch ( error ) {
132
+ // payments with insufficient funds error are still created in trolley,
133
+ // and they are storred as "pending".
134
+ // no need to do anything. just log a warning, and move on
135
+ if ( isInsufficientFundsError ( error ) ) {
136
+ this . logger . warn (
137
+ `Insufficient funds while processing payment: ${ error . validationErrors } ` ,
138
+ ) ;
139
+ return ;
140
+ }
141
+
142
+ this . logger . error (
143
+ `Failed to process trolley payment batch: ${ error . message } ` ,
144
+ error . validationErrors
145
+ ? { validationErrors : error . validationErrors }
146
+ : undefined ,
147
+ ) ;
148
+ throw new Error ( 'Failed to process trolley payment batch!' ) ;
99
149
}
100
150
}
101
151
}
0 commit comments