Skip to content

Commit 41b95c1

Browse files
authored
Merge pull request #60 from topcoder-platform/PM-1201_sync-payments-with-legacy
PM-1201 - sync payments with legacy
2 parents 86c1b99 + 1c6ff07 commit 41b95c1

11 files changed

+275
-68
lines changed

src/api/admin/admin.controller.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,12 @@ export class AdminController {
171171
}
172172

173173
const result = await this.adminService.updateWinnings(body, user.id);
174+
175+
result.status = ResponseStatusType.SUCCESS;
174176
if (result.error) {
175177
result.status = ResponseStatusType.ERROR;
176178
}
177179

178-
result.status = ResponseStatusType.SUCCESS;
179-
180180
return result;
181181
}
182182

@@ -200,12 +200,12 @@ export class AdminController {
200200
@Param('winningID') winningId: string,
201201
): Promise<ResponseDto<WinningAuditDto[]>> {
202202
const result = await this.adminService.getWinningAudit(winningId);
203+
204+
result.status = ResponseStatusType.SUCCESS;
203205
if (result.error) {
204206
result.status = ResponseStatusType.ERROR;
205207
}
206208

207-
result.status = ResponseStatusType.SUCCESS;
208-
209209
return result;
210210
}
211211

@@ -230,12 +230,12 @@ export class AdminController {
230230
@Param('winningID') winningId: string,
231231
): Promise<ResponseDto<AuditPayoutDto[]>> {
232232
const result = await this.adminService.getWinningAuditPayout(winningId);
233+
234+
result.status = ResponseStatusType.SUCCESS;
233235
if (result.error) {
234236
result.status = ResponseStatusType.ERROR;
235237
}
236238

237-
result.status = ResponseStatusType.SUCCESS;
238-
239239
return result;
240240
}
241241
}

src/api/admin/admin.module.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import { Module } from '@nestjs/common';
22
import { AdminController } from './admin.controller';
33
import { AdminService } from './admin.service';
4-
import { TaxFormRepository } from '../repository/taxForm.repo';
5-
import { PaymentMethodRepository } from '../repository/paymentMethod.repo';
64
import { WinningsRepository } from '../repository/winnings.repo';
75
import { TopcoderModule } from 'src/shared/topcoder/topcoder.module';
86
import { PaymentsModule } from 'src/shared/payments';
97

108
@Module({
119
imports: [TopcoderModule, PaymentsModule],
1210
controllers: [AdminController],
13-
providers: [
14-
AdminService,
15-
TaxFormRepository,
16-
PaymentMethodRepository,
17-
WinningsRepository,
18-
],
11+
providers: [AdminService, WinningsRepository],
1912
})
2013
export class AdminModule {}

src/api/admin/admin.service.ts

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ import {
66
Logger,
77
} from '@nestjs/common';
88

9-
import { PrismaPromise } from '@prisma/client';
9+
import { Prisma } from '@prisma/client';
1010
import { PrismaService } from 'src/shared/global/prisma.service';
1111
import { PaymentsService } from 'src/shared/payments';
1212

13-
import { TaxFormRepository } from '../repository/taxForm.repo';
14-
import { PaymentMethodRepository } from '../repository/paymentMethod.repo';
1513
import { ResponseDto } from 'src/dto/api-response.dto';
1614
import { PaymentStatus } from 'src/dto/payment.dto';
1715
import { WinningAuditDto, AuditPayoutDto } from './dto/audit.dto';
1816
import { WinningUpdateRequestDto } from './dto/winnings.dto';
17+
import {
18+
AdminPaymentUpdateData,
19+
TopcoderChallengesService,
20+
} from 'src/shared/topcoder/challenges.service';
1921

2022
/**
2123
* The admin winning service.
@@ -30,11 +32,14 @@ export class AdminService {
3032
*/
3133
constructor(
3234
private readonly prisma: PrismaService,
33-
private readonly taxFormRepo: TaxFormRepository,
34-
private readonly paymentMethodRepo: PaymentMethodRepository,
3535
private readonly paymentsService: PaymentsService,
36+
private readonly tcChallengesService: TopcoderChallengesService,
3637
) {}
3738

39+
private getWinningById(winningId: string) {
40+
return this.prisma.winnings.findFirst({ where: { winning_id: winningId } });
41+
}
42+
3843
private getPaymentsByWinningsId(winningsId: string, paymentId?: string) {
3944
return this.prisma.payment.findMany({
4045
where: {
@@ -79,7 +84,9 @@ export class AdminService {
7984
releaseDate = await this.getPaymentReleaseDateByWinningsId(winningsId);
8085
}
8186

82-
const transactions: PrismaPromise<any>[] = [];
87+
const transactions: ((
88+
tx: Prisma.TransactionClient,
89+
) => Promise<unknown>)[] = [];
8390
const now = new Date().getTime();
8491
payments.forEach((payment) => {
8592
if (
@@ -108,8 +115,8 @@ export class AdminService {
108115
if (sinceRelease < 12) {
109116
errMessage = `Cannot put a processing payment back to owed, unless it's been processing for at least 12 hours. Currently it's only been ${sinceRelease.toFixed(1)} hours`;
110117
} else {
111-
transactions.push(
112-
this.markPaymentReleaseAsFailedByWinningsId(winningsId),
118+
transactions.push((tx) =>
119+
this.markPaymentReleaseAsFailedByWinningsId(winningsId, tx),
113120
);
114121
}
115122
} else {
@@ -137,30 +144,32 @@ export class AdminService {
137144
throw new BadRequestException(errMessage);
138145
}
139146

140-
transactions.push(
147+
transactions.push((tx) =>
141148
this.updatePaymentStatus(
142149
userId,
143150
winningsId,
144151
payment.payment_id,
145152
payment.payment_status,
146153
body.paymentStatus,
147-
version,
154+
version++,
155+
tx,
148156
),
149157
);
150-
version += 1;
158+
151159
paymentStatus = body.paymentStatus as PaymentStatus;
152160

153161
if (body.paymentStatus === PaymentStatus.OWED) {
154162
needsReconciliation = true;
155163
}
156164

157165
if (payment.installment_number === 1) {
158-
transactions.push(
166+
transactions.push((tx) =>
159167
this.addAudit(
160168
userId,
161169
winningsId,
162170
`Modified payment status from ${payment.payment_status} to ${body.paymentStatus}`,
163171
body.auditNote,
172+
tx,
164173
),
165174
);
166175
}
@@ -186,24 +195,25 @@ export class AdminService {
186195
);
187196
}
188197

189-
transactions.push(
198+
transactions.push((tx) =>
190199
this.updateReleaseDate(
191200
userId,
192201
winningsId,
193202
payment.payment_id,
194203
newReleaseDate,
195-
version,
204+
version++,
205+
tx,
196206
),
197207
);
198-
version += 1;
199208

200209
if (payment.installment_number === 1) {
201-
transactions.push(
210+
transactions.push((tx) =>
202211
this.addAudit(
203212
userId,
204213
winningsId,
205214
`Modified release date from ${payment.release_date?.toISOString()} to ${newReleaseDate.toISOString()}`,
206215
body.auditNote,
216+
tx,
207217
),
208218
);
209219
}
@@ -218,7 +228,7 @@ export class AdminService {
218228
) {
219229
// ideally we should be maintaining the original split of the payment amount between installments - but we aren't really using splits anymore
220230
if (payment.installment_number === 1) {
221-
transactions.push(
231+
transactions.push((tx) =>
222232
this.updatePaymentAmount(
223233
userId,
224234
winningsId,
@@ -227,20 +237,22 @@ export class AdminService {
227237
body.paymentAmount,
228238
body.paymentAmount,
229239
version,
240+
tx,
230241
),
231242
);
232243

233-
transactions.push(
244+
transactions.push((tx) =>
234245
this.addAudit(
235246
userId,
236247
winningsId,
237248
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
238249
`Modified payment amount from ${payment.total_amount} to ${body.paymentAmount.toFixed(2)}`,
239250
body.auditNote,
251+
tx,
240252
),
241253
);
242254
} else {
243-
transactions.push(
255+
transactions.push((tx) =>
244256
this.updatePaymentAmount(
245257
userId,
246258
winningsId,
@@ -249,15 +261,43 @@ export class AdminService {
249261
0,
250262
body.paymentAmount,
251263
version,
264+
tx,
252265
),
253266
);
254267
}
255268
}
256269
});
257270

258-
if (transactions.length > 0) {
259-
await this.prisma.$transaction(transactions);
260-
}
271+
transactions.push(async () => {
272+
const winning = await this.getWinningById(winningsId);
273+
if (!winning) {
274+
this.logger.error(
275+
`Error updating legacy system for winning ${winningsId}. Winning not found!`,
276+
);
277+
throw new Error(
278+
`Error updating legacy system for winning ${winningsId}. Winning not found!`,
279+
);
280+
}
281+
282+
const payoutData: AdminPaymentUpdateData = {
283+
userId: +winning.winner_id,
284+
status: body.paymentStatus,
285+
amount: body.paymentAmount,
286+
releaseDate: body.releaseDate,
287+
};
288+
289+
await this.tcChallengesService.updateLegacyPayments(
290+
winning.external_id as string,
291+
payoutData,
292+
);
293+
});
294+
295+
// Run all transaction tasks in a single prisma transaction
296+
await this.prisma.$transaction(async (tx) => {
297+
for (const transaction of transactions) {
298+
await transaction(tx);
299+
}
300+
});
261301

262302
if (needsReconciliation) {
263303
const winning = await this.prisma.winnings.findFirst({
@@ -320,8 +360,11 @@ export class AdminService {
320360
return paymentReleases?.release_date;
321361
}
322362

323-
private markPaymentReleaseAsFailedByWinningsId(winningsId: string) {
324-
return this.prisma.payment_releases.updateMany({
363+
private markPaymentReleaseAsFailedByWinningsId(
364+
winningsId: string,
365+
tx?: Prisma.TransactionClient,
366+
) {
367+
return (tx ?? this.prisma).payment_releases.updateMany({
325368
where: {
326369
payment_release_associations: {
327370
some: {
@@ -346,19 +389,22 @@ export class AdminService {
346389
oldPaymentStatus: string | null,
347390
newPaymentStatus: PaymentStatus,
348391
currentVersion: number,
392+
tx?: Prisma.TransactionClient,
349393
) {
350394
let setDatePaidNull = false;
351-
if ([
352-
PaymentStatus.PAID,
353-
PaymentStatus.PROCESSING,
354-
PaymentStatus.RETURNED,
355-
PaymentStatus.FAILED,
356-
].includes(oldPaymentStatus as PaymentStatus) &&
395+
if (
396+
[
397+
PaymentStatus.PAID,
398+
PaymentStatus.PROCESSING,
399+
PaymentStatus.RETURNED,
400+
PaymentStatus.FAILED,
401+
].includes(oldPaymentStatus as PaymentStatus) &&
357402
newPaymentStatus === PaymentStatus.OWED
358403
) {
359404
setDatePaidNull = true;
360405
}
361-
return this.prisma.payment.update({
406+
407+
return (tx ?? this.prisma).payment.update({
362408
where: {
363409
payment_id: paymentId,
364410
winnings_id: winningsId,
@@ -379,8 +425,9 @@ export class AdminService {
379425
winningsId: string,
380426
action: string,
381427
auditNote?: string,
428+
tx?: Prisma.TransactionClient,
382429
) {
383-
return this.prisma.audit.create({
430+
return (tx ?? this.prisma).audit.create({
384431
data: {
385432
user_id: userId,
386433
winnings_id: winningsId,
@@ -396,8 +443,9 @@ export class AdminService {
396443
paymentId: string,
397444
newReleaseDate: Date,
398445
currentVersion: number,
446+
tx?: Prisma.TransactionClient,
399447
) {
400-
return this.prisma.payment.update({
448+
return (tx ?? this.prisma).payment.update({
401449
where: {
402450
payment_id: paymentId,
403451
winnings_id: winningsId,
@@ -427,8 +475,9 @@ export class AdminService {
427475
grossAmount: number,
428476
totalAmount: number,
429477
currentVersion: number,
478+
tx?: Prisma.TransactionClient,
430479
) {
431-
return this.prisma.payment.update({
480+
return (tx ?? this.prisma).payment.update({
432481
where: {
433482
payment_id: paymentId,
434483
winnings_id: winningsId,
@@ -461,11 +510,12 @@ export class AdminService {
461510
*/
462511
async getWinningAudit(
463512
winningId: string,
513+
tx?: Prisma.TransactionClient,
464514
): Promise<ResponseDto<WinningAuditDto[]>> {
465515
const result = new ResponseDto<WinningAuditDto[]>();
466516

467517
try {
468-
const audits = await this.prisma.audit.findMany({
518+
const audits = await (tx ?? this.prisma).audit.findMany({
469519
where: {
470520
winnings_id: {
471521
equals: winningId,
@@ -501,11 +551,14 @@ export class AdminService {
501551
*/
502552
async getWinningAuditPayout(
503553
winningId: string,
554+
tx?: Prisma.TransactionClient,
504555
): Promise<ResponseDto<AuditPayoutDto[]>> {
505556
const result = new ResponseDto<AuditPayoutDto[]>();
506557

507558
try {
508-
const paymentReleases = await this.prisma.payment_releases.findMany({
559+
const paymentReleases = await (
560+
tx ?? this.prisma
561+
).payment_releases.findMany({
509562
where: {
510563
payment_release_associations: {
511564
some: {

src/api/user/user.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ export class UserController {
6262
const result = await this.winningsRepo.searchWinnings(
6363
body as WinningRequestDto,
6464
);
65+
66+
result.status = ResponseStatusType.SUCCESS;
6567
if (result.error) {
6668
result.status = ResponseStatusType.ERROR;
6769
}
6870

69-
result.status = ResponseStatusType.SUCCESS;
70-
7171
return result;
7272
}
7373
}

0 commit comments

Comments
 (0)