Skip to content

Commit 1206ee4

Browse files
authored
Merge pull request #126 from topcoder-platform/fix-ba-consume
Fix ba consume
2 parents f86bd98 + 6cbda6b commit 1206ee4

3 files changed

Lines changed: 68 additions & 16 deletions

File tree

src/api/challenges/challenges.service.ts

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -470,25 +470,34 @@ export class ChallengesService {
470470

471471
async generateChallengePayments(challengeId: string, userId: string) {
472472
const challenge = await this.getChallenge(challengeId);
473+
this.logger.log(`Fetched challenge ${challengeId}`);
473474

474475
if (!challenge) {
476+
this.logger.error(`Challenge not found: ${challengeId}`);
475477
throw new Error('Challenge not found!');
476478
}
477479

480+
this.logger.log(`Challenge ${challenge.id} - "${challenge.name}" with status "${challenge.status}" retrieved`);
481+
478482
const allowedStatuses = [
479483
ChallengeStatuses.Completed.toLowerCase(),
480484
ChallengeStatuses.CancelledFailedReview.toLowerCase(),
481485
];
482486

483487
if (!allowedStatuses.includes(challenge.status.toLowerCase())) {
488+
this.logger.error(
489+
`Challenge ${challenge.id} isn't in a payable status: ${challenge.status}`,
490+
);
484491
throw new Error("Challenge isn't in a payable status!");
485492
}
486493

487494
// need to read for update (LOCK the rows)
495+
this.logger.log(`Attempting to acquire lock for challenge ${challenge.id}`);
488496
try {
489497
await this.prisma.challenge_lock.create({
490498
data: { external_id: challenge.id },
491499
});
500+
this.logger.log(`Lock acquired for challenge ${challenge.id}`);
492501
} catch (err: any) {
493502
if (err.code === 'P2002') {
494503
this.logger.log(`Challenge Lock already acquired for ${challenge.id}`);
@@ -497,27 +506,49 @@ export class ChallengesService {
497506
`Challenge Lock already acquired for ${challenge.id}`,
498507
);
499508
}
509+
this.logger.error(
510+
`Failed to acquire lock for challenge ${challenge.id}`,
511+
err.message ?? err,
512+
);
500513
throw err;
501514
}
502515

503516
try {
517+
this.logger.log(`Starting payment creation for challenge ${challenge.id}`);
504518
await this.createPayments(challenge, userId);
519+
this.logger.log(`Payment creation completed for challenge ${challenge.id}`);
505520
} catch (error) {
506-
if (error.message.includes('Lock already acquired')) {
521+
this.logger.error(
522+
`Error while creating payments for challenge ${challenge.id}`,
523+
error.message ?? error,
524+
);
525+
if (
526+
error &&
527+
(typeof error.message === 'string') &&
528+
error.message.includes('Lock already acquired')
529+
) {
530+
this.logger.log(`Conflict detected while creating payments for ${challenge.id}`);
507531
throw new ConflictException(
508532
'Another payment operation is in progress.',
509533
);
510534
} else {
511535
throw error;
512536
}
513537
} finally {
514-
await this.prisma.challenge_lock
515-
.deleteMany({
538+
try {
539+
const result = await this.prisma.challenge_lock.deleteMany({
516540
where: { external_id: challenge.id },
517-
})
518-
.catch(() => {
519-
// swallow errors if lock was already released
520541
});
542+
this.logger.log(
543+
`Released lock for challenge ${challenge.id}. Rows deleted: ${result.count}`,
544+
);
545+
} catch (releaseErr) {
546+
// swallow errors if lock was already released but log for observability
547+
this.logger.error(
548+
`Failed to release lock for challenge ${challenge.id}`,
549+
releaseErr.message ?? releaseErr,
550+
);
551+
}
521552
}
522553
}
523554
}

src/shared/topcoder/billing-accounts.service.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ const { TOPCODER_API_V6_BASE_URL, TGBillingAccounts } = ENV_CONFIG;
88

99
interface LockAmountDTO {
1010
challengeId: string;
11-
lockAmount: number;
11+
amount: number;
1212
}
1313
interface ConsumeAmountDTO {
1414
challengeId: string;
15-
consumeAmount: number;
16-
markup?: number;
15+
amount: number;
1716
}
1817

1918
export interface BAValidation {
@@ -40,7 +39,7 @@ export class BillingAccountsService {
4039
`${TOPCODER_API_V6_BASE_URL}/billing-accounts/${billingAccountId}/lock-amount`,
4140
{
4241
method: 'PATCH',
43-
body: JSON.stringify({ param: dto }),
42+
body: JSON.stringify(dto),
4443
},
4544
);
4645
} catch (err: any) {
@@ -49,7 +48,7 @@ export class BillingAccountsService {
4948
'Failed to lock challenge amount',
5049
);
5150
throw new Error(
52-
`Budget Error: Requested amount $${dto.lockAmount} exceeds available budget for Billing Account #${billingAccountId}.
51+
`Budget Error: Requested amount $${dto.amount} exceeds available budget for Billing Account #${billingAccountId}.
5352
Please contact the Topcoder Project Manager for further assistance.`,
5453
);
5554
}
@@ -63,7 +62,7 @@ export class BillingAccountsService {
6362
`${TOPCODER_API_V6_BASE_URL}/billing-accounts/${billingAccountId}/consume-amount`,
6463
{
6564
method: 'PATCH',
66-
body: JSON.stringify({ param: dto }),
65+
body: JSON.stringify(dto),
6766
},
6867
);
6968
} catch (err: any) {
@@ -111,7 +110,7 @@ export class BillingAccountsService {
111110

112111
await this.lockAmount(billingAccountId, {
113112
challengeId: baValidation.challengeId!,
114-
lockAmount:
113+
amount:
115114
(rollback ? prevAmount : currAmount) * (1 + baValidation.markup!),
116115
});
117116
} else if (status === ChallengeStatuses.Completed.toLowerCase()) {
@@ -125,9 +124,8 @@ export class BillingAccountsService {
125124
if (currAmount !== prevAmount) {
126125
await this.consumeAmount(billingAccountId, {
127126
challengeId: baValidation.challengeId!,
128-
consumeAmount:
127+
amount:
129128
(rollback ? prevAmount : currAmount) * (1 + baValidation.markup!),
130-
markup: baValidation.markup,
131129
});
132130
}
133131
} else if (
@@ -155,7 +153,7 @@ export class BillingAccountsService {
155153
if (currAmount !== prevAmount) {
156154
await this.lockAmount(billingAccountId, {
157155
challengeId: baValidation.challengeId!,
158-
lockAmount: rollback ? prevAmount : 0,
156+
amount: rollback ? prevAmount : 0,
159157
});
160158
}
161159
}

src/shared/topcoder/topcoder-m2m.service.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,29 @@ export class TopcoderM2MService {
9696
const response = await fetch(url, finalOptions);
9797

9898
if (!response.ok) {
99+
let responseBody: unknown;
100+
try {
101+
const text = await response.text();
102+
try {
103+
responseBody = JSON.parse(text);
104+
} catch {
105+
responseBody = text;
106+
}
107+
} catch (e) {
108+
responseBody = `Failed to read response body: ${e?.message ?? e}`;
109+
}
110+
111+
this.logger.error(
112+
'M2M fetch failed',
113+
{
114+
url: String(url),
115+
method: (finalOptions.method ?? 'GET'),
116+
status: response.status,
117+
statusText: response.statusText,
118+
requestBody: (finalOptions as any).body,
119+
responseBody,
120+
},
121+
);
99122
// Optional: You could throw a custom error here
100123
throw new Error(`HTTP error! Status: ${response.status}`);
101124
}

0 commit comments

Comments
 (0)