Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 60 additions & 16 deletions src/api/challenges/challenges.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import {
Challenge,
ChallengeResource,
ChallengeReview,
Prize,
ResourceRole,
Winner,
} from './models';
import { BillingAccountsService } from 'src/shared/topcoder/billing-accounts.service';
import { TopcoderM2MService } from 'src/shared/topcoder/topcoder-m2m.service';
Expand Down Expand Up @@ -117,9 +119,12 @@ export class ChallengesService {
}
}

generateWinnersPayments(challenge: Challenge): PaymentPayload[] {
const { prizeSets, winners } = challenge;

generateWinnersPayments(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The function signature has been changed to accept winners and prizes as separate parameters, but the original challenge parameter already contains these properties. This change could lead to redundancy and potential inconsistencies if the winners or prizes parameters differ from those in the challenge object. Consider using the properties directly from the challenge object to maintain consistency and reduce the risk of errors.

challenge: Challenge,
winners: Winner[],
prizes: Prize[],
type?: WinningsCategory,
): PaymentPayload[] {
const isCancelledFailedReview =
challenge.status.toLowerCase() ===
ChallengeStatuses.CancelledFailedReview.toLowerCase();
Expand All @@ -128,6 +133,53 @@ export class ChallengesService {
return [];
}

return winners.map((winner) => ({
handle: winner.handle,
amount: prizes[winner.placement - 1].value,
userId: winner.userId.toString(),
type:
type ??
(challenge.task.isTask
? WinningsCategory.TASK_PAYMENT
: WinningsCategory.CONTEST_PAYMENT),
description:
challenge.type === 'Task'
? challenge.name
: `${challenge.name} - ${placeToOrdinal(winner.placement)} Place`,
}));
}

generateCheckpointWinnersPayments(challenge: Challenge): PaymentPayload[] {
const { prizeSets, checkpointWinners } = challenge;

// generate placement payments
const checkpointPrizes = orderBy(
find(prizeSets, { type: 'CHECKPOINT' })?.prizes,
'value',
'desc',
);

if ((checkpointPrizes?.length ?? 0) < (checkpointWinners?.length ?? 0)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
The error message could be more informative by including the actual numbers of checkpoint winners and prizes. Consider including these values to aid debugging.

throw new Error(
'Task has incorrect number of checkpoint prizes! There are more checkpoint winners than checkpoint prizes!',
);
}

if (!checkpointPrizes?.length) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 maintainability]
The check for !checkpointPrizes?.length is redundant since the previous condition already ensures that checkpointPrizes has at least as many elements as checkpointWinners. Consider removing this check to simplify the code.

return [];
}

return this.generateWinnersPayments(
challenge,
checkpointWinners,
checkpointPrizes,
WinningsCategory.CONTEST_CHECKPOINT_PAYMENT,
);
}

generatePlacementWinnersPayments(challenge: Challenge): PaymentPayload[] {
const { prizeSets, winners } = challenge;

// generate placement payments
const placementPrizes = orderBy(
find(prizeSets, { type: 'PLACEMENT' })?.prizes,
Expand All @@ -141,18 +193,7 @@ export class ChallengesService {
);
}

return winners.map((winner) => ({
handle: winner.handle,
amount: placementPrizes[winner.placement - 1].value,
userId: winner.userId.toString(),
type: challenge.task.isTask
? WinningsCategory.TASK_PAYMENT
: WinningsCategory.CONTEST_PAYMENT,
description:
challenge.type === 'Task'
? challenge.name
: `${challenge.name} - ${placeToOrdinal(winner.placement)} Place`,
}));
return this.generateWinnersPayments(challenge, winners, placementPrizes);
}

generateCopilotPayment(
Expand Down Expand Up @@ -284,7 +325,9 @@ export class ChallengesService {
throw new Error('Missing challenge resources!');
}

const winnersPayments = this.generateWinnersPayments(challenge);
const winnersPayments = this.generatePlacementWinnersPayments(challenge);
const checkpointPayments =
this.generateCheckpointWinnersPayments(challenge);
const copilotPayments = this.generateCopilotPayment(
challenge,
challengeResources.copilot,
Expand Down Expand Up @@ -315,6 +358,7 @@ export class ChallengesService {

const payments: PaymentPayload[] = [
...winnersPayments,
...checkpointPayments,
...copilotPayments,
...reviewersPayments,
];
Expand Down
3 changes: 2 additions & 1 deletion src/api/challenges/models/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export interface Challenge {
created: string;
updated: string;
overview: PrizeOverview;
winners: Winner[]; // Replace with type if needed
winners: Winner[];
checkpointWinners: Winner[];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
Consider adding validation or constraints to ensure that checkpointWinners is correctly populated and does not contain duplicates or invalid entries. This will help maintain data integrity and prevent potential issues with incorrect winner data.

numOfSubmissions: number;
numOfCheckpointSubmissions: number;
numOfRegistrants: number;
Expand Down