@@ -49,6 +49,24 @@ import { ProjectWithRelationsDto } from './dto/project-response.dto';
4949import { UpgradeProjectDto } from './dto/upgrade-project.dto' ;
5050import { UpdateProjectDto } from './dto/update-project.dto' ;
5151
52+ const BILLING_MARKUP_COPILOT_ROLES = [
53+ UserRole . COPILOT ,
54+ UserRole . TC_COPILOT ,
55+ ] ;
56+
57+ const BILLING_MARKUP_VISIBLE_HUMAN_ROLES = [
58+ ...ADMIN_ROLES ,
59+ UserRole . MANAGER ,
60+ UserRole . TOPCODER_MANAGER ,
61+ UserRole . TOPCODER_ACCOUNT_MANAGER ,
62+ UserRole . COPILOT_MANAGER ,
63+ UserRole . PROJECT_MANAGER ,
64+ UserRole . TASK_MANAGER ,
65+ UserRole . TOPCODER_TASK_MANAGER ,
66+ UserRole . TALENT_MANAGER ,
67+ UserRole . TOPCODER_TALENT_MANAGER ,
68+ ] ;
69+
5270interface PaginatedProjectResponse {
5371 data : ProjectWithRelationsDto [ ] ;
5472 page : number ;
@@ -1038,8 +1056,9 @@ export class ProjectService {
10381056 * @param user Authenticated caller context.
10391057 * @returns Default billing account details.
10401058 * @throws NotFoundException When project or billing account is missing.
1041- * @security Removes `markup` for non-machine callers to avoid exposing
1042- * markup details to interactive users.
1059+ * @security Removes `markup` for copilot-only callers while preserving the
1060+ * existing response shape for M2M, Project Manager, Talent Manager, and
1061+ * administrator callers.
10431062 */
10441063 async getProjectBillingAccount (
10451064 projectId : string ,
@@ -1083,7 +1102,7 @@ export class ProjectService {
10831102 tcBillingAccountId : projectBillingAccountId ,
10841103 } ;
10851104
1086- if ( this . isMachinePrincipal ( user ) ) {
1105+ if ( ! this . shouldHideBillingAccountMarkupForCopilot ( user ) ) {
10871106 return billingAccount ;
10881107 }
10891108
@@ -2175,6 +2194,37 @@ export class ProjectService {
21752194 return false ;
21762195 }
21772196
2197+ /**
2198+ * Determines whether project billing-account markup must be hidden.
2199+ *
2200+ * Copilot-only human callers should not receive raw billing-account markup.
2201+ * Manager, Talent Manager, and administrator roles retain the existing
2202+ * response shape even when the same token also carries a copilot role.
2203+ *
2204+ * @param user Authenticated caller context.
2205+ * @returns `true` when billing-account markup should be removed.
2206+ */
2207+ private shouldHideBillingAccountMarkupForCopilot ( user : JwtUser ) : boolean {
2208+ if ( this . isMachinePrincipal ( user ) ) {
2209+ return false ;
2210+ }
2211+
2212+ const roles = user . roles || [ ] ;
2213+ const hasCopilotRole = this . permissionService . hasIntersection (
2214+ roles ,
2215+ BILLING_MARKUP_COPILOT_ROLES ,
2216+ ) ;
2217+
2218+ if ( ! hasCopilotRole ) {
2219+ return false ;
2220+ }
2221+
2222+ return ! this . permissionService . hasIntersection (
2223+ roles ,
2224+ BILLING_MARKUP_VISIBLE_HUMAN_ROLES ,
2225+ ) ;
2226+ }
2227+
21782228 /**
21792229 * Safely extracts template phase objects from JSON payload.
21802230 *
0 commit comments