feat(certificate): add score breakdown and recommendations for certificate progression

This commit is contained in:
Torsten Schulz (local)
2026-08-28 11:50:30 +02:00
parent 89215793ab
commit 4bcf9041af
4 changed files with 121 additions and 0 deletions

View File

@@ -282,6 +282,22 @@ function getScoreThresholdForCertificate(level) {
return 0;
}
function buildCertificateScoreComponent(key, current, points, weight, steps) {
const next = steps.find((step) => step.points > points) || null;
return {
key,
current,
points,
maxPoints: 5,
weight,
contribution: Number((points * weight).toFixed(2)),
nextValue: next?.value ?? null,
nextPoints: next?.points ?? null,
gain: next ? Number(((next.points - points) * weight).toFixed(2)) : 0,
maxed: !next,
};
}
async function calcRegionalSellPrice(product, knowledgeFactor, regionId, worthPercent = null) {
// Wenn worthPercent nicht übergeben wurde, hole es aus der Datenbank
if (worthPercent === null) {
@@ -3122,6 +3138,36 @@ class FalukantService extends BaseService {
const nextCertificate = Math.min(5, currentCertificate + 1);
const nextThreshold = CERTIFICATE_THRESHOLDS[nextCertificate] || null;
const nextScoreThreshold = getScoreThresholdForCertificate(nextCertificate);
const scoreBreakdown = [
buildCertificateScoreComponent('avgKnowledge', avgKnowledge, knowledgePoints, 0.45, [
{ value: 20, points: 1 }, { value: 35, points: 2 }, { value: 50, points: 3 },
{ value: 65, points: 4 }, { value: 80, points: 5 },
]),
buildCertificateScoreComponent('completedProductions', completedProductions, productionPoints, 0.30, [
{ value: 5, points: 1 }, { value: 20, points: 2 }, { value: 50, points: 3 },
{ value: 100, points: 4 }, { value: 200, points: 5 },
]),
buildCertificateScoreComponent('officePoints', highestOfficeRank, officePoints, 0.08, [
{ value: 1, points: 1 }, { value: 2, points: 2 }, { value: 3, points: 3 },
{ value: 4, points: 4 }, { value: 5, points: 5 },
]),
buildCertificateScoreComponent('reputationPoints', reputation, reputationPoints, 0.07, [
{ value: 20, points: 1 }, { value: 40, points: 2 }, { value: 60, points: 3 },
{ value: 75, points: 4 }, { value: 90, points: 5 },
]),
buildCertificateScoreComponent('housePoints', housePosition, housePoints, 0.05, [
{ value: 2, points: 1 }, { value: 4, points: 2 }, { value: 6, points: 3 },
{ value: 8, points: 4 }, { value: 10, points: 5 },
]),
buildCertificateScoreComponent('nobilityPoints', nobilityLevel, nobilityPoints, 0.05, [
{ value: 2, points: 1 }, { value: 3, points: 2 }, { value: 4, points: 3 },
{ value: 5, points: 4 }, { value: 6, points: 5 },
]),
];
const scoreGap = Math.max(0, Number((nextScoreThreshold - score).toFixed(2)));
const scoreRecommendations = scoreBreakdown
.filter((component) => !component.maxed && component.gain > 0)
.sort((a, b) => b.gain - a.gain);
const currentValues = {
avgKnowledge,
@@ -3194,6 +3240,9 @@ class FalukantService extends BaseService {
score: Number(score.toFixed(2)),
targetCertificate,
nextScoreThreshold,
scoreGap,
scoreBreakdown,
scoreRecommendations,
currentValues,
nextRequirements,
statusRequirement,