vbv/client/src/pages/competence/utils.ts

149 lines
4.6 KiB
TypeScript

import type { StatusCount } from "@/components/ui/ItProgress.vue";
import { percentToRoundedGrade } from "@/services/assignmentService";
import type { CompetenceCertificate, CompetenceCertificateAssignment } from "@/types";
import dayjs from "dayjs";
import _ from "lodash";
import log from "loglevel";
export function assignmentsMaxEvaluationPoints(
assignments: CompetenceCertificateAssignment[]
): number {
return _.sum(
assignments
.filter((a) => a.completions[0]?.completion_status === "EVALUATION_SUBMITTED")
.map((a) => a.max_points)
);
}
export function assignmentsUserPoints(assignments: CompetenceCertificateAssignment[]) {
return +_.sum(
assignments
.filter((a) => a.completions?.[0]?.completion_status === "EVALUATION_SUBMITTED")
.map((a) => a.completions?.[0]?.evaluation_points_final ?? 0)
).toFixed(1);
}
/**
* Calculates the grade by summing up all the weighted percentage of points of each assignment.
*
* @param assignments - list of assignments
* @param roundedToHalfGrade - should the grade be rounded?
*/
export function calcCompetenceCertificateGrade(
assignments: CompetenceCertificateAssignment[],
roundedToHalfGrade: boolean = true
) {
const evaluatedAssignments = assignments.filter(
(a) => a.completions?.[0]?.completion_status === "EVALUATION_SUBMITTED"
);
// sum((points_x / max_points) * weight_x)
const adjustedResults = evaluatedAssignments.map((a) => {
return (
((a.completions?.[0]?.evaluation_points_final ?? 0) / a.max_points) *
a.competence_certificate_weight
);
});
// count only assignments with weight
const adjustedAssignmentCount = _.sum(
evaluatedAssignments.map((a) => a.competence_certificate_weight)
);
if (adjustedAssignmentCount === 0) {
return undefined;
}
return percentToRoundedGrade(
_.sum(adjustedResults) / adjustedAssignmentCount,
roundedToHalfGrade
);
}
export function calcCompetencesTotalGrade(
competenceCertificates: CompetenceCertificate[]
) {
// für das Total der Kompetenznote werden jeweils die gerundenten Noten der
// einzelnen Kompetenznachweise verwendet und dann noch einmal gerundet.
const competenceCertificateGrades = competenceCertificates
.map((cc) => {
return calcCompetenceCertificateGrade(cc.assignments);
})
.filter((g) => {
// filter out "empty" grades
return !!g;
});
const percentGraded =
// @ts-ignore `g` cannot be undefined here
_.sum(competenceCertificateGrades.map((g) => g - 1)) /
(competenceCertificateGrades.length * 5);
return percentToRoundedGrade(percentGraded);
}
export function competenceCertificateProgressStatusCount(
assignments: CompetenceCertificateAssignment[]
) {
const numAssignmentsEvaluated = assignments.filter(
(a) => a.completions?.[0]?.completion_status === "EVALUATION_SUBMITTED"
).length;
return {
SUCCESS: numAssignmentsEvaluated,
UNKNOWN: assignments.length - numAssignmentsEvaluated,
FAIL: 0,
} as StatusCount;
}
export function mergeCompetenceCertificates(
competenceCertificates: CompetenceCertificate[]
) {
const groupedCompetenceCertificates: Record<
string,
Array<CompetenceCertificate>
> = {};
competenceCertificates.forEach((certificate) => {
if (!certificate) {
return;
}
if (!groupedCompetenceCertificates[certificate.id]) {
groupedCompetenceCertificates[certificate.id] = [];
}
groupedCompetenceCertificates[certificate.id].push(certificate);
});
log.debug(
`Found ${Object.keys(groupedCompetenceCertificates).length} competence certificates over all course sessions`
);
return Object.values(groupedCompetenceCertificates).map((certificates) => {
const mergedCertificate: CompetenceCertificate = {
...certificates[0],
assignments: [],
};
certificates.forEach((certificate) => {
certificate.assignments.forEach((assignment) => {
const existingAssignment = mergedCertificate.assignments.find(
(a) => a.id === assignment.id
);
if (!existingAssignment) {
mergedCertificate.assignments.push(assignment);
} else if (
assignment.completions?.[0] != null &&
(existingAssignment.completions?.[0] == null ||
dayjs(existingAssignment.completions[0].evaluation_submitted_at).isBefore(
assignment.completions[0].evaluation_submitted_at
))
) {
mergedCertificate.assignments.splice(
mergedCertificate.assignments.findIndex((a) => a.id === assignment.id),
1
);
mergedCertificate.assignments.push(assignment);
}
});
});
return mergedCertificate;
});
}