Skip to content

Commit 9e875e1

Browse files
authored
fix: duplicate payment generation (#74)
* on re-opening a completed challenge and closing it again * the updateForACL method is re-triggered leading to re-creation * of already created payments. This pull request prevents the * re-generation of payments by checking if payments have already * been created for a given challenge id Signed-off-by: Rakib Ansary <rakibansary@topcoder.com>
1 parent f03939c commit 9e875e1

File tree

2 files changed

+44
-34
lines changed

2 files changed

+44
-34
lines changed

src/domain/Challenge.ts

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import ChallengeScheduler from "../util/ChallengeScheduler";
4141
import { BAValidation, lockConsumeAmount } from "../api/BillingAccount";
4242
import { ChallengeEstimator } from "../util/ChallengeEstimator";
4343
import { V5_TRACK_IDS_TO_NAMES, V5_TYPE_IDS_TO_NAMES } from "../common/ConversionMap";
44-
import PaymentCreator, { PaymentDetail } from "../util/PaymentCreator";
44+
import WalletApi, { PaymentDetail } from "../util/WalletApi";
4545
import { getChallengeResources } from "../api/v5Api";
4646
import m2mToken from "../helpers/MachineToMachineToken";
4747

@@ -909,11 +909,21 @@ class ChallengeDomain extends CoreOperations<Challenge, CreateChallengeInput> {
909909
title: string,
910910
payments: UpdateChallengeInputForACL_PaymentACL[]
911911
): Promise<number> {
912+
const token = await m2mToken.getM2MToken();
913+
912914
console.log(
913915
`Generating payments for challenge ${challengeId}, ${title} with payments ${JSON.stringify(
914916
payments
915917
)} for challenge type ${challengeType}`
916918
);
919+
920+
// Check if payment already exists
921+
const existingPayments = await WalletApi.getPaymentsByChallengeId(challengeId, token);
922+
if (existingPayments.length > 0) {
923+
console.log(`Payments already exist for challenge ${challengeId}, skipping payment generation`);
924+
return 0;
925+
}
926+
917927
let totalAmount = 0;
918928
// TODO: Make this list exhaustive
919929
const mapType = (type: string) => {
@@ -934,43 +944,22 @@ class ChallengeDomain extends CoreOperations<Challenge, CreateChallengeInput> {
934944
const nPayments = payments.length;
935945
for (let i = 0; i < nPayments; i++) {
936946
const payment = payments[i];
937-
let details: PaymentDetail[] = [];
947+
let details: PaymentDetail[] = [
948+
{
949+
totalAmount: payment.amount,
950+
grossAmount: payment.amount,
951+
installmentNumber: 1,
952+
currency: "USD",
953+
},
954+
];
938955

939956
let description = title;
940957

941-
// TODO: Make this a more dynamic calculation
942-
// TODO: splitRatio should be from challenge data
943958
if (payment.type === "placement") {
944-
const grossAmount1 = payment.amount * 0.75;
945-
const grossAmount2 = payment.amount * 0.25;
946-
details = [
947-
{
948-
totalAmount: payment.amount,
949-
grossAmount: grossAmount1,
950-
installmentNumber: 1,
951-
currency: "USD",
952-
},
953-
{
954-
totalAmount: payment.amount,
955-
grossAmount: grossAmount2,
956-
installmentNumber: 2,
957-
currency: "USD",
958-
},
959-
];
960-
961959
description =
962960
challengeType != "Task"
963961
? `${title} - ${this.placeToOrdinal(placementMap[payment.handle])} Place`
964962
: title;
965-
} else {
966-
details = [
967-
{
968-
totalAmount: payment.amount,
969-
grossAmount: payment.amount,
970-
installmentNumber: 1,
971-
currency: "USD",
972-
},
973-
];
974963
}
975964

976965
totalAmount += payment.amount;
@@ -995,7 +984,7 @@ class ChallengeDomain extends CoreOperations<Challenge, CreateChallengeInput> {
995984
}
996985

997986
console.log("Generate payment with payload", payload);
998-
await PaymentCreator.createPayment(payload, await m2mToken.getM2MToken());
987+
await WalletApi.createPayment(payload, token);
999988
}
1000989

1001990
return totalAmount;

src/util/PaymentCreator.ts renamed to src/util/WalletApi.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface PaymentPayload {
2222
}
2323

2424
// TODO: Move this to a processor that handles challenge completion events from Harmony
25-
class PaymentCreator {
25+
class WalletApi {
2626
private static readonly BASE_URL =
2727
(process.env.TOPCODER_API_ENDPOINT ?? "https://api.topcoder-dev.com/v5") + "/payments";
2828

@@ -40,7 +40,7 @@ class PaymentCreator {
4040

4141
try {
4242
console.log(payload.externalId, "Creating payment. Attempt", attempts, payload);
43-
const response = await axios.post(PaymentCreator.BASE_URL + "/winnings", payload, config);
43+
const response = await axios.post(WalletApi.BASE_URL + "/winnings", payload, config);
4444
console.log("Payment created", response.data);
4545
return response;
4646
} catch (error) {
@@ -55,6 +55,27 @@ class PaymentCreator {
5555
}
5656
}
5757
}
58+
59+
async getPaymentsByChallengeId(challengeId: string, token?: string): Promise<any[]> {
60+
const config = {
61+
headers: {
62+
"Content-Type": "application/json",
63+
...(token ? { Authorization: `Bearer ${token}` } : {}),
64+
},
65+
};
66+
67+
const payload = {
68+
externalIds: [challengeId],
69+
};
70+
71+
try {
72+
const response = await axios.post(WalletApi.BASE_URL + "/winnings/list", payload, config);
73+
return response.data.data;
74+
} catch (err) {
75+
return [];
76+
}
77+
}
78+
5879
}
5980

60-
export default new PaymentCreator();
81+
export default new WalletApi();

0 commit comments

Comments
 (0)