@@ -33,8 +33,11 @@ import {
3333 TopcoderChallengeInfo ,
3434 TopcoderChallengesService ,
3535} from 'src/shared/topcoder/challenges.service' ;
36- import { WinningPaymentDetailsDto } from './dto/payment-details.dto' ;
3736import { resolveChallengeMemberPaymentAmount } from 'src/shared/payments/challenge-payment-amount.util' ;
37+ import {
38+ PaymentCycle ,
39+ WinningPaymentDetailsDto ,
40+ } from './dto/payment-details.dto' ;
3841
3942const PAYMENT_DECIMAL_PLACES = 2 ;
4043const BUDGET_LEDGER_DECIMAL_PLACES = 4 ;
@@ -262,6 +265,13 @@ export class AdminService {
262265 assignment . standardHoursPerWeek !== null
263266 ? Number ( assignment . standardHoursPerWeek )
264267 : undefined ;
268+ const standardHoursPerDay =
269+ assignment ?. standardHoursPerDay !== undefined &&
270+ assignment . standardHoursPerDay !== null
271+ ? Number ( assignment . standardHoursPerDay )
272+ : Number . isFinite ( standardHoursPerWeek )
273+ ? Number ( ( ( standardHoursPerWeek ?? 0 ) / 5 ) . toFixed ( 2 ) )
274+ : undefined ;
265275 const projectId = engagement . projectId ?? engagement . project ?. id ;
266276 const projectName =
267277 ( engagement . projectName ?? engagement . project ?. name ) ?. trim ( ) ?? undefined ;
@@ -289,6 +299,11 @@ export class AdminService {
289299 ? durationMonths
290300 : undefined ,
291301 ratePerHour : assignment ?. ratePerHour ?. trim ( ) ?? undefined ,
302+ paymentCycle : ( assignment ?. paymentCycle ?. trim ( ) ||
303+ 'WEEKLY' ) as PaymentCycle ,
304+ standardHoursPerDay : Number . isFinite ( standardHoursPerDay )
305+ ? standardHoursPerDay
306+ : undefined ,
292307 standardHoursPerWeek : Number . isFinite ( standardHoursPerWeek )
293308 ? standardHoursPerWeek
294309 : undefined ,
@@ -1187,6 +1202,38 @@ export class AdminService {
11871202 return result ;
11881203 }
11891204
1205+ /**
1206+ * Resolves the payment approver handle from the audit entry that moved the
1207+ * winning from `ON_HOLD_ADMIN` to `OWED`.
1208+ */
1209+ private async resolvePaymentApproverHandleFromAudit (
1210+ winningsId : string ,
1211+ ) : Promise < string | undefined > {
1212+ try {
1213+ const audits = await this . prisma . audit . findMany ( {
1214+ where : { winnings_id : winningsId } ,
1215+ orderBy : { created_at : 'desc' } ,
1216+ take : 200 ,
1217+ } ) ;
1218+ const approverAudit = audits . find (
1219+ ( audit ) =>
1220+ typeof audit . action === 'string' &&
1221+ audit . action . includes ( 'ON_HOLD_ADMIN' ) &&
1222+ audit . action . includes ( 'OWED' ) &&
1223+ audit . action . indexOf ( 'ON_HOLD_ADMIN' ) < audit . action . indexOf ( 'OWED' ) ,
1224+ ) ;
1225+
1226+ if ( ! approverAudit ?. user_id ) {
1227+ return undefined ;
1228+ }
1229+
1230+ return this . getPaymentCreatorHandle ( String ( approverAudit . user_id ) ) ;
1231+ } catch {
1232+ // approver is optional — ignore failures
1233+ return undefined ;
1234+ }
1235+ }
1236+
11901237 private async buildTaskDetails (
11911238 winningsId : string ,
11921239 externalId : string | undefined ,
@@ -1220,27 +1267,8 @@ export class AdminService {
12201267 }
12211268 }
12221269
1223- try {
1224- const audits = await this . prisma . audit . findMany ( {
1225- where : { winnings_id : winningsId } ,
1226- orderBy : { created_at : 'desc' } ,
1227- take : 200 ,
1228- } ) ;
1229- const approverAudit = audits . find (
1230- ( a ) =>
1231- typeof a . action === 'string' &&
1232- a . action . includes ( 'ON_HOLD_ADMIN' ) &&
1233- a . action . includes ( 'OWED' ) &&
1234- a . action . indexOf ( 'ON_HOLD_ADMIN' ) < a . action . indexOf ( 'OWED' ) ,
1235- ) ;
1236- if ( approverAudit ?. user_id ) {
1237- const userId = String ( approverAudit . user_id ) ;
1238- const handle = await this . getPaymentCreatorHandle ( userId ) ;
1239- taskDetails . paymentApproverHandle = handle ?? undefined ;
1240- }
1241- } catch {
1242- // approver is optional — ignore failures
1243- }
1270+ taskDetails . paymentApproverHandle =
1271+ await this . resolvePaymentApproverHandleFromAudit ( winningsId ) ;
12441272
12451273 return taskDetails ;
12461274 }
@@ -1294,13 +1322,15 @@ export class AdminService {
12941322 return result ;
12951323 }
12961324
1325+ const paymentApproverHandle =
1326+ await this . resolvePaymentApproverHandleFromAudit ( winningsId ) ;
1327+
12971328 if ( assignmentLookupId ) {
12981329 try {
12991330 const assignmentContext =
13001331 await this . topcoderEngagementsService . getAssignmentContextById (
13011332 assignmentLookupId ,
13021333 ) ;
1303-
13041334 result . data . engagementDetails = {
13051335 assignmentId : assignmentContext . assignmentId ,
13061336 engagementId : assignmentContext . engagementId ,
@@ -1312,9 +1342,18 @@ export class AdminService {
13121342 : undefined ,
13131343 durationMonths : assignmentContext . durationMonths ?? undefined ,
13141344 ratePerHour : assignmentContext . ratePerHour ?? undefined ,
1345+ paymentCycle : ( assignmentContext . paymentCycle ??
1346+ 'WEEKLY' ) as PaymentCycle ,
1347+ standardHoursPerDay :
1348+ assignmentContext . standardHoursPerDay ??
1349+ ( assignmentContext . standardHoursPerWeek !== undefined &&
1350+ assignmentContext . standardHoursPerWeek !== null
1351+ ? Number ( ( assignmentContext . standardHoursPerWeek / 5 ) . toFixed ( 2 ) )
1352+ : undefined ) ,
13151353 standardHoursPerWeek :
13161354 assignmentContext . standardHoursPerWeek ?? undefined ,
13171355 otherRemarks : assignmentContext . otherRemarks ?? undefined ,
1356+ paymentApproverHandle,
13181357 } ;
13191358
13201359 return result ;
@@ -1339,11 +1378,14 @@ export class AdminService {
13391378 assignmentId ,
13401379 ) ;
13411380
1342- result . data . engagementDetails = this . buildEngagementDetailsFromEngagement (
1343- engagement ,
1344- assignment ,
1345- assignmentId ,
1346- ) ;
1381+ result . data . engagementDetails = {
1382+ ...this . buildEngagementDetailsFromEngagement (
1383+ engagement ,
1384+ assignment ,
1385+ assignmentId ,
1386+ ) ,
1387+ paymentApproverHandle,
1388+ } ;
13471389 } catch ( error ) {
13481390 this . logger . warn (
13491391 `Failed to enrich winning ${ winningsId } with engagement details` ,
0 commit comments