@@ -79,7 +79,9 @@ const PROJECT_LOOKUP_TARGETS: ProjectLookupTarget[] = [
7979 * Missing DB URLs or missing referenced rows produce empty lookup mappings
8080 * rather than failing the billing account response. Projects API lookups try
8181 * both the configured connection search path and the explicit `projects`
82- * schema, because deployment URLs are not always schema-qualified.
82+ * schema, because deployment URLs are not always schema-qualified. Project
83+ * ids are compared as normalized text so legacy varchar columns and newer
84+ * numeric columns both work.
8385 */
8486@Injectable ( )
8587export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
@@ -237,7 +239,8 @@ export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
237239 * members require non-deleted membership. Callers without a billing-account
238240 * Topcoder role can require the membership to be a management/copilot
239241 * project role. The Projects DB table lookup is tolerant of URLs with or
240- * without a `schema=projects` search path.
242+ * without a `schema=projects` search path, and of project id columns stored
243+ * as either numeric or varchar values.
241244 *
242245 * @param billingAccountId Topcoder billing-account id from the detail route.
243246 * @param userId Topcoder user id from the authenticated caller; optional
@@ -299,12 +302,10 @@ export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
299302 SELECT true AS "hasAccess"
300303 FROM ${ target . projectsTable } project
301304 INNER JOIN ${ target . projectMembersTable } project_member
302- ON project_member."projectId" = project."id"
303- WHERE project."billingAccountId" = ${ BigInt (
304- normalizedBillingAccountId ,
305- ) }
305+ ON project_member."projectId"::text = project."id"::text
306+ WHERE project."billingAccountId"::text = ${ normalizedBillingAccountId }
306307 AND project."deletedAt" IS NULL
307- AND project_member."userId" = ${ BigInt ( membershipUserId ) }
308+ AND project_member."userId"::text = ${ membershipUserId }
308309 ${ projectRoleFilter }
309310 AND project_member."deletedAt" IS NULL
310311 LIMIT 1
@@ -349,7 +350,7 @@ export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
349350 Prisma . sql `
350351 SELECT true AS "hasAccess"
351352 FROM ${ target . projectsTable } project
352- WHERE project."billingAccountId" = ${ BigInt ( billingAccountId ) }
353+ WHERE project."billingAccountId"::text = ${ billingAccountId }
353354 AND project."deletedAt" IS NULL
354355 LIMIT 1
355356 ` ,
@@ -601,7 +602,8 @@ export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
601602 * @param projectIds Candidate project ids from line-item references.
602603 * @returns Set of candidate project ids with an active project member row.
603604 * The lookup checks both the configured search path and the explicit
604- * `projects` schema.
605+ * `projects` schema. Id comparisons are text-normalized so both legacy
606+ * varchar columns and newer numeric columns work.
605607 */
606608 private async getAccessibleProjectIdsForUser (
607609 userId : string ,
@@ -635,10 +637,8 @@ export class ExternalBudgetEntryLookupService implements OnModuleDestroy {
635637 Prisma . sql `
636638 SELECT DISTINCT "projectId"::text AS "projectId"
637639 FROM ${ target . projectMembersTable }
638- WHERE "userId" = ${ BigInt ( userId ) }
639- AND "projectId" IN (${ Prisma . join (
640- uniqueProjectIds . map ( ( projectId ) => BigInt ( projectId ) ) ,
641- ) } )
640+ WHERE "userId"::text = ${ userId }
641+ AND "projectId"::text IN (${ Prisma . join ( uniqueProjectIds ) } )
642642 AND "deletedAt" IS NULL
643643 ` ,
644644 ) ;
0 commit comments