From 160f8d2a0bdc4a2bb8547a9884c10f84a152dab5 Mon Sep 17 00:00:00 2001 From: Tofik Hasanov Date: Tue, 24 Mar 2026 19:23:31 -0400 Subject: [PATCH] fix(frameworks): respect securityTrainingStepEnabled in overview people score The overview scores endpoint always required all 5 CompAI training videos (sat-1 through sat-5) to be completed, ignoring the org's securityTrainingStepEnabled setting. This caused orgs that disabled CompAI training videos to show incorrect people completion counts (e.g., 2/9 instead of 9/9). Now fetches the org setting and skips training video checks when disabled, matching the behavior of the People page and portal. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../frameworks/frameworks-scores.helper.ts | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/api/src/frameworks/frameworks-scores.helper.ts b/apps/api/src/frameworks/frameworks-scores.helper.ts index c7578602c..9fbe6e406 100644 --- a/apps/api/src/frameworks/frameworks-scores.helper.ts +++ b/apps/api/src/frameworks/frameworks-scores.helper.ts @@ -12,7 +12,7 @@ const SIX_MONTHS_MS = 6 * 30 * 24 * 60 * 60 * 1000; const TRAINING_VIDEO_IDS = ['sat-1', 'sat-2', 'sat-3', 'sat-4', 'sat-5']; export async function getOverviewScores(organizationId: string) { - const [allPolicies, allTasks, employees, onboarding] = await Promise.all([ + const [allPolicies, allTasks, employees, onboarding, org] = await Promise.all([ db.policy.findMany({ where: { organizationId } }), db.task.findMany({ where: { organizationId } }), db.member.findMany({ @@ -23,8 +23,14 @@ export async function getOverviewScores(organizationId: string) { where: { organizationId }, select: { triggerJobId: true }, }), + db.organization.findUnique({ + where: { id: organizationId }, + select: { securityTrainingStepEnabled: true }, + }), ]); + const securityTrainingStepEnabled = org?.securityTrainingStepEnabled === true; + // Policy breakdown const publishedPolicies = allPolicies.filter((p) => p.status === 'published'); const draftPolicies = allPolicies.filter((p) => p.status === 'draft'); @@ -54,25 +60,30 @@ export async function getOverviewScores(organizationId: string) { p.isRequiredToSign && p.status === 'published' && !p.isArchived, ); - const trainingCompletions = - await db.employeeTrainingVideoCompletion.findMany({ - where: { memberId: { in: activeEmployees.map((e) => e.id) } }, - }); + const trainingCompletions = securityTrainingStepEnabled + ? await db.employeeTrainingVideoCompletion.findMany({ + where: { memberId: { in: activeEmployees.map((e) => e.id) } }, + }) + : []; for (const emp of activeEmployees) { const hasAcceptedAllPolicies = requiredPolicies.length === 0 || requiredPolicies.every((p) => p.signedBy.includes(emp.id)); - const empCompletions = trainingCompletions.filter( - (c) => c.memberId === emp.id, - ); - const completedVideoIds = empCompletions - .filter((c) => c.completedAt !== null) - .map((c) => c.videoId); - const hasCompletedAllTraining = TRAINING_VIDEO_IDS.every((vid) => - completedVideoIds.includes(vid), - ); + const hasCompletedAllTraining = securityTrainingStepEnabled + ? (() => { + const empCompletions = trainingCompletions.filter( + (c) => c.memberId === emp.id, + ); + const completedVideoIds = empCompletions + .filter((c) => c.completedAt !== null) + .map((c) => c.videoId); + return TRAINING_VIDEO_IDS.every((vid) => + completedVideoIds.includes(vid), + ); + })() + : true; if (hasAcceptedAllPolicies && hasCompletedAllTraining) { completedMembers++;