added transaction for calculating the pqq final answer score
This commit is contained in:
@@ -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,
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { verifyMinglarAdminToken } from '@/common/middlewares/jwt/authForMinglarAdmin';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
||||
import { PrismaService } from '../../../../../common/database/prisma.service';
|
||||
import { safeHandler } from '../../../../../common/utils/handlers/safeHandler';
|
||||
import ApiError from '../../../../../common/utils/helper/ApiError';
|
||||
import { string } from 'zod';
|
||||
import { PrePopulateService } from '../../../../prepopulate/services/prepopulate.service';
|
||||
import { MinglarService } from '../../../services/minglar.service';
|
||||
import { verifyMinglarAdminHostToken } from '@/common/middlewares/jwt/authForMinglarAdmin&Host';
|
||||
|
||||
const prismaService = new PrismaService();
|
||||
const minglarService = new MinglarService(prismaService);
|
||||
@@ -27,7 +26,7 @@ export const handler = safeHandler(async (
|
||||
}
|
||||
|
||||
// Verify token and get user info
|
||||
const userInfo = await verifyMinglarAdminHostToken(token);
|
||||
const userInfo = await verifyMinglarAdminToken(token);
|
||||
|
||||
const hostXid = Number(event.pathParameters?.id)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import { sendAMEmailForHostAssign } from './AMEmail.service';
|
||||
|
||||
@Injectable()
|
||||
export class MinglarService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
constructor(private prisma: PrismaService) { }
|
||||
|
||||
async createPassword(user_xid: number, password: string): Promise<boolean> {
|
||||
// Find user by id
|
||||
@@ -203,16 +203,36 @@ export class MinglarService {
|
||||
}
|
||||
|
||||
async getAllHostActivityForMinglar(search?: string, hostXid?: number) {
|
||||
return await this.prisma.activities.findMany({
|
||||
return await this.prisma.activities.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
hostXid: hostXid,
|
||||
},
|
||||
include: {
|
||||
ActivitiesMedia: true,
|
||||
ActivityAmDetails: true,
|
||||
ActivitiesMedia: {
|
||||
select: {
|
||||
id: true,
|
||||
mediaFileName: true,
|
||||
mediaType: true,
|
||||
displayOrder: true,
|
||||
}
|
||||
},
|
||||
ActivityAmDetails: {
|
||||
select: {
|
||||
accountManager: {
|
||||
select: {
|
||||
id: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
profileImage: true,
|
||||
emailAddress: true,
|
||||
roleXid: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
activityType: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -614,7 +634,7 @@ export class MinglarService {
|
||||
if (
|
||||
userStatus &&
|
||||
userStatus.trim().toLowerCase() ===
|
||||
MINGLAR_STATUS_DISPLAY.NEW.toLowerCase()
|
||||
MINGLAR_STATUS_DISPLAY.NEW.toLowerCase()
|
||||
) {
|
||||
filters.adminStatusInternal = MINGLAR_STATUS_INTERNAL.ADMIN_TO_REVIEW;
|
||||
}
|
||||
@@ -872,7 +892,7 @@ export class MinglarService {
|
||||
|
||||
if (
|
||||
hostDetails.adminStatusInternal !==
|
||||
MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED &&
|
||||
MINGLAR_STATUS_INTERNAL.AM_NOT_ASSIGNED &&
|
||||
hostDetails.adminStatusDisplay !== MINGLAR_STATUS_DISPLAY.AM_NOT_ASSIGNED
|
||||
) {
|
||||
throw new ApiError(400, 'Invalid host status');
|
||||
|
||||
Reference in New Issue
Block a user