added transaction for calculating the pqq final answer score

This commit is contained in:
2025-11-27 19:16:46 +05:30
parent b0bae33b6e
commit 326ea2f96b
3 changed files with 184 additions and 110 deletions

View File

@@ -39,7 +39,7 @@ interface HostDocumentInput {
@Injectable()
export class HostService {
constructor(private prisma: PrismaService) {}
constructor(private prisma: PrismaService) { }
async createHost(data: CreateHostDto) {
return this.prisma.user.create({ data });
@@ -720,119 +720,132 @@ export class HostService {
// }
async calculatePqqScoreForUser(activityXid: number) {
// 1. Get all headers for this activity (user's answers)
const answers = await this.prisma.activityPQQheader.findMany({
where: { activityXid },
include: {
pqqQuestions: {
include: {
pqqSubCategories: {
include: {
category: true,
return await this.prisma.$transaction(async (tx) => {
// 1. Get all headers for this activity (user's answers)
const answers = await this.prisma.activityPQQheader.findMany({
where: { activityXid },
include: {
pqqQuestions: {
include: {
pqqSubCategories: {
include: {
category: true,
},
},
},
},
pqqAnswers: true,
},
pqqAnswers: true,
},
});
});
if (!answers.length) {
return {
overallPercentage: 0,
categoryWise: {},
};
}
// Prepare accumulators
let totalUserPoints = 0;
let totalMaxPoints = 0;
// For category-wise scoring
const categories: Record<
number,
{
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}
> = {};
for (const item of answers) {
const question = item.pqqQuestions;
const answer = item.pqqAnswers;
const maxPoints = question.maxPoints;
const userPoints = answer.answerPoints;
totalUserPoints += userPoints;
totalMaxPoints += maxPoints;
// Category
const category = question.pqqSubCategories.category;
const categoryId = category.id;
if (!categories[categoryId]) {
categories[categoryId] = {
categoryId,
categoryName: category.categoryName,
userPoints: 0,
maxPoints: 0,
if (!answers.length) {
return {
overallPercentage: 0,
categoryWise: {},
};
}
categories[categoryId].userPoints += userPoints;
categories[categoryId].maxPoints += maxPoints;
}
// Prepare accumulators
let totalUserPoints = 0;
let totalMaxPoints = 0;
// Overall percent
const overallPercentage =
totalMaxPoints > 0 ? (totalUserPoints / totalMaxPoints) * 100 : 0;
// For category-wise scoring
const categories: Record<
number,
{
categoryId: number;
categoryName: string;
userPoints: number;
maxPoints: number;
}
> = {};
for (const item of answers) {
const question = item.pqqQuestions;
const answer = item.pqqAnswers;
const maxPoints = question.maxPoints;
const userPoints = answer.answerPoints;
totalUserPoints += userPoints;
totalMaxPoints += maxPoints;
// Category
const category = question.pqqSubCategories.category;
const categoryId = category.id;
if (!categories[categoryId]) {
categories[categoryId] = {
categoryId,
categoryName: category.categoryName,
userPoints: 0,
maxPoints: 0,
};
}
categories[categoryId].userPoints += userPoints;
categories[categoryId].maxPoints += maxPoints;
}
// Overall percent
const overallPercentage =
totalMaxPoints > 0 ? (totalUserPoints / totalMaxPoints) * 100 : 0;
if (overallPercentage > 50) {
await this.prisma.activities.update({
where: {
id: activityXid
},
data: {
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.UNDER_REVIEW,
activityDisplayStatus: ACTIVITY_DISPLAY_STATUS.UNDER_REVIEW
}
})
} else {
await this.prisma.activities.update({
where: {
id: activityXid
},
data: {
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.PQQ_FAILED,
activityDisplayStatus: ACTIVITY_DISPLAY_STATUS.PQQ_FAILED
}
})
}
// ---------- 🔥 ONLY FIRST 2 CATEGORIES ----------
const categoryArray = Object.values(categories);
// Sort by categoryId (or change to displayOrder if needed)
categoryArray.sort((a, b) => a.categoryId - b.categoryId);
// Take only first 2 categories
const topTwo = categoryArray.slice(0, 2);
const categoryWise: Record<string, number> = {};
for (const c of topTwo) {
categoryWise[c.categoryName] =
c.maxPoints > 0 ? (c.userPoints / c.maxPoints) * 100 : 0;
}
if (overallPercentage > 50) {
await this.prisma.activities.update({
where: {
id: activityXid
},
data: {
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.UNDER_REVIEW,
activityDisplayStatus: ACTIVITY_DISPLAY_STATUS.UNDER_REVIEW
totalScore: overallPercentage,
sustainabilityScore: categoryWise.Sustainability,
safetyScore: categoryWise.Safety
}
})
} else {
await this.prisma.activities.update({
where: {
id: activityXid
},
data: {
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.PQQ_FAILED,
activityDisplayStatus: ACTIVITY_DISPLAY_STATUS.PQQ_FAILED
}
})
}
// ---------- 🔥 ONLY FIRST 2 CATEGORIES ----------
const categoryArray = Object.values(categories);
// Sort by categoryId (or change to displayOrder if needed)
categoryArray.sort((a, b) => a.categoryId - b.categoryId);
// Take only first 2 categories
const topTwo = categoryArray.slice(0, 2);
const categoryWise: Record<string, number> = {};
for (const c of topTwo) {
categoryWise[c.categoryName] =
c.maxPoints > 0 ? (c.userPoints / c.maxPoints) * 100 : 0;
}
// Return final score object
return {
overallPercentage,
categoryWise,
};
// Return final score object
return {
overallPercentage,
categoryWise,
};
});
}
async createHeader(
@@ -927,10 +940,52 @@ export class HostService {
return await this.prisma.activityPQQheader.findMany({
where: { isActive: true },
include: {
pqqQuestions: true,
ActivityPQQSuggestions: true,
pqqAnswers: true,
ActivityPQQSupportings: true,
pqqQuestions: {
select: {
questionName: true,
maxPoints: true,
displayOrder: true,
pqqSubCategories: {
select: {
id: true,
subCategoryName: true,
displayOrder: true,
category: {
select: {
id: true,
categoryName: true,
displayOrder: true,
}
}
}
}
}
},
ActivityPQQSuggestions: {
select: {
id: true,
title: true,
comments: true,
isReviewed: true,
reviewedBy: true,
reviewedOn: true,
}
},
pqqAnswers: {
select: {
id: true,
displayOrder: true,
answerName: true,
answerPoints: true
}
},
ActivityPQQSupportings: {
select: {
id: true,
mediaFileName: true,
mediaType: true,
}
},
},
});
}