apps/recallassess/recallassess-api/src/api/client/reports/reports.controller.ts
api/client/reports
Unified Reports Controller
All reports follow the pattern: GET /api/client/reports/{report-name}
This makes it easy to add new reports in the future - just add a new route handler.
Methods |
|
| Async getAdvancedGroupPerformanceReport | |||||||||||||||||||||
getAdvancedGroupPerformanceReport(auth: CLAuthData, group?: string, learningGroup?: string, course?: string, period?: string, status?: string)
|
|||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
|||||||||||||||||||||
|
Get advanced group performance report GET /api/client/reports/advanced-group-performance
Parameters :
Returns :
unknown
|
| Async getAdvancedIndividualPerformanceReport | ||||||||||||||||||||||||
getAdvancedIndividualPerformanceReport(auth: CLAuthData, accountType?: string, course?: string, stage?: string, performanceLevel?: string, lastActivePeriod?: string, search?: string)
|
||||||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||||||||
|
Get advanced individual performance report GET /api/client/reports/advanced-individual-performance
Parameters :
Returns :
unknown
|
| Async getAssessmentCompletionReport | ||||||||||||||||||||||||
getAssessmentCompletionReport(auth: CLAuthData, assessmentType?: string, completionStatus?: string, period?: string, course?: string, learningGroup?: string, search?: string)
|
||||||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||||||||
|
Get assessment completion report GET /api/client/reports/assessment-completion
Parameters :
Returns :
unknown
|
| Async getBehaviouralAssessmentAnalysisReport | ||||||||||||||||||||||||
getBehaviouralAssessmentAnalysisReport(auth: CLAuthData, group?: string, assessmentType?: string, course?: string, scoreRange?: string, period?: string, assessmentPeriod?: string)
|
||||||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||||||||
|
Get behavioural assessment analysis report GET /api/client/reports/behavioural-assessment-analysis
Parameters :
Returns :
unknown
|
| Async getCourseLicenseUtilizationReport | ||||||||||||||||||
getCourseLicenseUtilizationReport(auth: CLAuthData, course?: string, learningGroup?: string, period?: string, utilizationStatus?: string)
|
||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||
|
Get course license utilization report GET /api/client/reports/course-license-utilization
Parameters :
|
| Async getParticipantRosterReport | ||||||||||||||||||
getParticipantRosterReport(auth: CLAuthData, status?: string, participantGroup?: string, sq?: string, period?: string)
|
||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||
|
Get participant roster report GET /api/client/reports/participant-roster
Parameters :
Returns :
unknown
|
| Async getPostBatAnalysis | ||||||
getPostBatAnalysis(auth: CLAuthData)
|
||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||
|
Get post-BAT analysis (placeholder participant list) GET /api/client/reports/post-bat-analysis NOTE:
Parameters :
Returns :
unknown
|
| Async getPreBatAnalysis | ||||||
getPreBatAnalysis(auth: CLAuthData)
|
||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||
|
Get pre-BAT analysis (placeholder participant list) GET /api/client/reports/pre-bat-analysis NOTE:
Parameters :
Returns :
unknown
|
| Async getStandardGroupPerformanceReport | |||||||||||||||||||||
getStandardGroupPerformanceReport(auth: CLAuthData, group?: string, learningGroup?: string, course?: string, period?: string, status?: string)
|
|||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
|||||||||||||||||||||
|
Get standard group performance report GET /api/client/reports/standard-group-performance
Parameters :
Returns :
unknown
|
| Async getStandardIndividualPerformanceReport | ||||||||||||||||||||||||
getStandardIndividualPerformanceReport(auth: CLAuthData, accountType?: string, course?: string, stage?: string, performanceLevel?: string, lastActivePeriod?: string, search?: string)
|
||||||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
||||||||||||||||||||||||
|
Get standard individual performance report GET /api/client/reports/standard-individual-performance
Parameters :
Returns :
unknown
|
| Async getTrainingImpactReport | |||||||||||||||||||||
getTrainingImpactReport(auth: CLAuthData, course?: string, accountType?: string, period?: string, impactLevel?: string, learningGroup?: string)
|
|||||||||||||||||||||
Decorators :
@HttpCode(HttpStatus.OK)
|
|||||||||||||||||||||
|
Get training impact report GET /api/client/reports/training-impact
Parameters :
Returns :
unknown
|
import { CLAuthData, ClientAuth } from "@api/shared/decorators";
import { Controller, Get, HttpCode, HttpStatus, Query } from "@nestjs/common";
import { CLAssessmentService } from "../assessment/assessment.service";
import { CLParticipantService } from "../participant/participant.service";
import { CourseLicenseUtilizationRowDto } from "../learning-group/dto";
import { CLLearningGroupService } from "../learning-group/learning-group.service";
/**
* Unified Reports Controller
*
* All reports follow the pattern: GET /api/client/reports/{report-name}
*
* This makes it easy to add new reports in the future - just add a new route handler.
*/
@Controller("api/client/reports")
export class CLReportsController {
constructor(
private readonly assessmentService: CLAssessmentService,
private readonly participantService: CLParticipantService,
private readonly learningGroupService: CLLearningGroupService,
) {}
/**
* Get participant roster report
* GET /api/client/reports/participant-roster
*/
@HttpCode(HttpStatus.OK)
@Get("participant-roster")
async getParticipantRosterReport(
@ClientAuth() auth: CLAuthData,
@Query("status") status?: string,
@Query("participantGroup") participantGroup?: string,
@Query("sq") sq?: string,
@Query("period") period?: string,
) {
const result = await this.participantService.getFilteredParticipants(
auth.companyId,
1,
1000, // Get up to 1000 participants for the report
sq,
status,
participantGroup,
auth.participantId,
auth.role,
);
// Explicitly return the data array - CLParticipantListResponse has a 'data' property
if (result && result.data && Array.isArray(result.data)) {
// Ensure each item has required fields
const validData = result.data.filter((item: any) => {
return item && (item.id || item.participant_id) && (item.full_name || (item.first_name || item.last_name));
});
return validData;
}
// Fallback: if result is already an array, return it
if (Array.isArray(result)) {
return result;
}
// If no data, return empty array
return [];
}
/**
* Get pre-BAT analysis (placeholder participant list)
* GET /api/client/reports/pre-bat-analysis
*
* NOTE:
* - Currently reuses participant list data as a placeholder,
* so the frontend can be wired end-to-end.
* - Replace with real pre-BAT aggregation logic when ready.
*/
@HttpCode(HttpStatus.OK)
@Get("pre-bat-analysis")
async getPreBatAnalysis(@ClientAuth() auth: CLAuthData) {
return this.participantService.getFilteredParticipants(
auth.companyId,
1,
100, // TODO: adjust pagination/filters for real pre-BAT report
undefined,
undefined,
undefined,
auth.participantId,
auth.role,
);
}
/**
* Get post-BAT analysis (placeholder participant list)
* GET /api/client/reports/post-bat-analysis
*
* NOTE:
* - Currently reuses participant list data as a placeholder,
* so the frontend can be wired end-to-end.
* - Replace with real post-BAT aggregation logic when ready.
*/
@HttpCode(HttpStatus.OK)
@Get("post-bat-analysis")
async getPostBatAnalysis(@ClientAuth() auth: CLAuthData) {
return this.participantService.getFilteredParticipants(
auth.companyId,
1,
100, // TODO: adjust pagination/filters for real post-BAT report
undefined,
undefined,
undefined,
auth.participantId,
auth.role,
);
}
/**
* Get course license utilization report
* GET /api/client/reports/course-license-utilization
*/
@HttpCode(HttpStatus.OK)
@Get("course-license-utilization")
async getCourseLicenseUtilizationReport(
@ClientAuth() auth: CLAuthData,
@Query("course") course?: string,
@Query("learningGroup") learningGroup?: string,
@Query("period") period?: string,
@Query("utilizationStatus") utilizationStatus?: string,
): Promise<CourseLicenseUtilizationRowDto[]> {
return this.learningGroupService.getCourseLicenseUtilization(auth.companyId, {
course,
learningGroup,
period,
utilizationStatus,
});
}
/**
* Get assessment completion report
* GET /api/client/reports/assessment-completion
*/
@HttpCode(HttpStatus.OK)
@Get("assessment-completion")
async getAssessmentCompletionReport(
@ClientAuth() auth: CLAuthData,
@Query("assessmentType") assessmentType?: string,
@Query("completionStatus") completionStatus?: string,
@Query("period") period?: string,
@Query("course") course?: string,
@Query("learningGroup") learningGroup?: string,
@Query("search") search?: string,
) {
return this.assessmentService.getAssessmentCompletionReport(auth.participantId, auth.companyId, {
assessmentType,
completionStatus,
period,
course,
learningGroup,
search,
});
}
/**
* Get standard individual performance report
* GET /api/client/reports/standard-individual-performance
*/
@HttpCode(HttpStatus.OK)
@Get("standard-individual-performance")
async getStandardIndividualPerformanceReport(
@ClientAuth() auth: CLAuthData,
@Query("accountType") accountType?: string,
@Query("course") course?: string,
@Query("stage") stage?: string,
@Query("performanceLevel") performanceLevel?: string,
@Query("lastActivePeriod") lastActivePeriod?: string,
@Query("search") search?: string,
) {
return this.assessmentService.getStandardIndividualPerformanceReport(auth.companyId, {
accountType,
course,
stage,
performanceLevel,
lastActivePeriod,
search,
});
}
/**
* Get advanced individual performance report
* GET /api/client/reports/advanced-individual-performance
*/
@HttpCode(HttpStatus.OK)
@Get("advanced-individual-performance")
async getAdvancedIndividualPerformanceReport(
@ClientAuth() auth: CLAuthData,
@Query("accountType") accountType?: string,
@Query("course") course?: string,
@Query("stage") stage?: string,
@Query("performanceLevel") performanceLevel?: string,
@Query("lastActivePeriod") lastActivePeriod?: string,
@Query("search") search?: string,
) {
// Get base data (this method doesn't accept filters yet)
const result = await this.assessmentService.getAdvancedIndividualPerformance(auth.companyId);
// Apply filters manually
let filtered = result;
if (course && course !== "all") {
filtered = filtered.filter((item) => String(item.courseId) === course);
}
if (search) {
const searchLower = search.toLowerCase();
filtered = filtered.filter(
(item) =>
item.participantName.toLowerCase().includes(searchLower) ||
(item.learningGroup && item.learningGroup.toLowerCase().includes(searchLower)) ||
item.courseTitle.toLowerCase().includes(searchLower),
);
}
// Note: accountType, stage, performanceLevel, and lastActivePeriod filters
// would require additional data from participants table, so they're not applied here
// but can be added if needed
return filtered;
}
/**
* Get standard group performance report
* GET /api/client/reports/standard-group-performance
*/
@HttpCode(HttpStatus.OK)
@Get("standard-group-performance")
async getStandardGroupPerformanceReport(
@ClientAuth() auth: CLAuthData,
@Query("group") group?: string,
@Query("learningGroup") learningGroup?: string,
@Query("course") course?: string,
@Query("period") period?: string,
@Query("status") status?: string,
) {
return this.assessmentService.getStandardGroupPerformanceReport(auth.companyId, {
group,
learningGroup,
course,
period,
status,
});
}
/**
* Get advanced group performance report
* GET /api/client/reports/advanced-group-performance
*/
@HttpCode(HttpStatus.OK)
@Get("advanced-group-performance")
async getAdvancedGroupPerformanceReport(
@ClientAuth() auth: CLAuthData,
@Query("group") group?: string,
@Query("learningGroup") learningGroup?: string,
@Query("course") course?: string,
@Query("period") period?: string,
@Query("status") status?: string,
) {
return this.assessmentService.getAdvancedGroupPerformanceReport(auth.companyId, {
group,
learningGroup,
course,
period,
status,
});
}
/**
* Get behavioural assessment analysis report
* GET /api/client/reports/behavioural-assessment-analysis
*/
@HttpCode(HttpStatus.OK)
@Get("behavioural-assessment-analysis")
async getBehaviouralAssessmentAnalysisReport(
@ClientAuth() auth: CLAuthData,
@Query("group") group?: string,
@Query("assessmentType") assessmentType?: string,
@Query("course") course?: string,
@Query("scoreRange") scoreRange?: string,
@Query("period") period?: string,
@Query("assessmentPeriod") assessmentPeriod?: string,
) {
return this.assessmentService.getBehaviouralAssessmentAnalysisReport(auth.companyId, {
group,
assessmentType,
course,
scoreRange,
period,
assessmentPeriod,
});
}
/**
* Get training impact report
* GET /api/client/reports/training-impact
*/
@HttpCode(HttpStatus.OK)
@Get("training-impact")
async getTrainingImpactReport(
@ClientAuth() auth: CLAuthData,
@Query("course") course?: string,
@Query("accountType") accountType?: string,
@Query("period") period?: string,
@Query("impactLevel") impactLevel?: string,
@Query("learningGroup") learningGroup?: string,
) {
return this.assessmentService.getTrainingImpactReport(auth.companyId, {
course,
accountType,
period,
impactLevel,
learningGroup,
});
}
}