forked from Yara724/api
Fix ratings and statistics
This commit is contained in:
@@ -211,6 +211,9 @@ export class FileRating {
|
||||
|
||||
@Prop({ type: Number, min: 0, max: 5 })
|
||||
guiltyVehicleIdentification: number;
|
||||
|
||||
@Prop({ type: Number, min: 0, max: 5 })
|
||||
botRating: number;
|
||||
}
|
||||
|
||||
export class PriceDrop {
|
||||
|
||||
@@ -69,6 +69,11 @@ export class ExpertInsurerController {
|
||||
);
|
||||
}
|
||||
|
||||
@Get("statistics")
|
||||
async getExpertStatistics(@CurrentUser() actor) {
|
||||
return await this.expertInsurerService.getExpertStatisticsReport(actor);
|
||||
}
|
||||
|
||||
@ApiParam({ name: "expertId" })
|
||||
@ApiQuery({ name: "role", enum: ["claim", "blame"] })
|
||||
@Get("/:expertId")
|
||||
@@ -120,13 +125,28 @@ export class ExpertInsurerController {
|
||||
example: 4,
|
||||
description: "تشخیص درست وسیله نقلیه مقصر",
|
||||
},
|
||||
botRating: {
|
||||
type: "number",
|
||||
minimum: 0,
|
||||
maximum: 5,
|
||||
example: 4,
|
||||
description: "برای امتیاز دادن به بات",
|
||||
},
|
||||
},
|
||||
required: [
|
||||
"collisionMethodAccuracy",
|
||||
"evaluationTimeliness",
|
||||
"accidentCauseAccuracy",
|
||||
"guiltyVehicleIdentification",
|
||||
"botRating",
|
||||
],
|
||||
example: {
|
||||
collisionMethodAccuracy: 4,
|
||||
evaluationTimeliness: 3,
|
||||
accidentCauseAccuracy: 5,
|
||||
guiltyVehicleIdentification: 4,
|
||||
botRating: 4,
|
||||
},
|
||||
},
|
||||
})
|
||||
@ApiParam({ name: "requestId" })
|
||||
|
||||
@@ -768,4 +768,141 @@ export class ExpertInsurerService {
|
||||
|
||||
return newBranch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comprehensive statistics for all experts of a client
|
||||
* Returns:
|
||||
* - Percentage of insurer's rating to BOT
|
||||
* - Percentage of expert's rating given by users
|
||||
* - Percentage of files that have objection
|
||||
* - Number of files created in the current month
|
||||
*/
|
||||
async getExpertStatisticsReport(actor: any) {
|
||||
const { clientKey } = actor;
|
||||
if (!clientKey) {
|
||||
throw new BadRequestException("Client key is required");
|
||||
}
|
||||
|
||||
const clientObjectId = new Types.ObjectId(clientKey);
|
||||
|
||||
// Get all claim files for this client
|
||||
const claimFiles = await this.claimRequestManagementModel
|
||||
.find({
|
||||
userClientKey: clientObjectId,
|
||||
})
|
||||
.lean();
|
||||
|
||||
// Calculate current month date range
|
||||
const now = new Date();
|
||||
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
||||
|
||||
// Filter files created this month
|
||||
const filesThisMonth = claimFiles.filter((file) => {
|
||||
const createdAt = new Date(file.createdAt);
|
||||
return createdAt >= monthStart && createdAt <= monthEnd;
|
||||
});
|
||||
|
||||
// Calculate statistics
|
||||
let totalInsurerRatings = 0;
|
||||
let totalBotRatings = 0;
|
||||
let filesWithInsurerRating = 0;
|
||||
let filesWithBotRating = 0;
|
||||
let filesWithUserRating = 0;
|
||||
let filesWithObjection = 0;
|
||||
|
||||
for (const file of claimFiles) {
|
||||
const insurerRating = file?.rating;
|
||||
const userRating = file?.userRating;
|
||||
const objection = file?.objection;
|
||||
|
||||
// Check for insurer rating (excluding botRating)
|
||||
if (insurerRating) {
|
||||
const insurerValues = [
|
||||
insurerRating.collisionMethodAccuracy,
|
||||
insurerRating.evaluationTimeliness,
|
||||
insurerRating.accidentCauseAccuracy,
|
||||
insurerRating.guiltyVehicleIdentification,
|
||||
].filter((val): val is number => typeof val === "number" && !isNaN(val));
|
||||
|
||||
if (insurerValues.length > 0) {
|
||||
filesWithInsurerRating++;
|
||||
const insurerAvg =
|
||||
insurerValues.reduce((a, b) => a + b, 0) / insurerValues.length;
|
||||
totalInsurerRatings += insurerAvg;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for bot rating (if botRating field exists in rating object)
|
||||
const botRating = (insurerRating as any)?.botRating;
|
||||
if (botRating !== undefined && !isNaN(botRating) && typeof botRating === "number") {
|
||||
filesWithBotRating++;
|
||||
totalBotRatings += botRating;
|
||||
}
|
||||
|
||||
// Check for user rating
|
||||
if (userRating) {
|
||||
filesWithUserRating++;
|
||||
}
|
||||
|
||||
// Check for objection
|
||||
if (objection) {
|
||||
filesWithObjection++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate percentages
|
||||
const totalFiles = claimFiles.length;
|
||||
|
||||
// Calculate average insurer rating (excluding botRating) and average bot rating
|
||||
const averageInsurerRating =
|
||||
filesWithInsurerRating > 0
|
||||
? totalInsurerRatings / filesWithInsurerRating
|
||||
: 0;
|
||||
const averageBotRating =
|
||||
filesWithBotRating > 0 ? totalBotRatings / filesWithBotRating : 0;
|
||||
|
||||
// Calculate percentage: (averageInsurerRating / averageBotRating) * 100
|
||||
// This shows what percentage the insurer rating is compared to bot rating
|
||||
const insurerToBotPercentage =
|
||||
averageBotRating > 0 && averageInsurerRating > 0
|
||||
? parseFloat(
|
||||
((averageInsurerRating / averageBotRating) * 100).toFixed(2),
|
||||
)
|
||||
: 0;
|
||||
|
||||
const userRatingPercentage =
|
||||
totalFiles > 0
|
||||
? parseFloat(((filesWithUserRating / totalFiles) * 100).toFixed(2))
|
||||
: 0;
|
||||
|
||||
const objectionPercentage =
|
||||
totalFiles > 0
|
||||
? parseFloat(((filesWithObjection / totalFiles) * 100).toFixed(2))
|
||||
: 0;
|
||||
|
||||
return {
|
||||
insurerToBotRatingPercentage: insurerToBotPercentage,
|
||||
userRatingPercentage: userRatingPercentage,
|
||||
objectionPercentage: objectionPercentage,
|
||||
filesCreatedThisMonth: filesThisMonth.length,
|
||||
totalFiles: totalFiles,
|
||||
breakdown: {
|
||||
filesWithInsurerRating,
|
||||
filesWithBotRating,
|
||||
filesWithUserRating,
|
||||
filesWithObjection,
|
||||
averageInsurerRating:
|
||||
filesWithInsurerRating > 0
|
||||
? parseFloat(
|
||||
(totalInsurerRatings / filesWithInsurerRating).toFixed(2),
|
||||
)
|
||||
: 0,
|
||||
averageBotRating:
|
||||
filesWithBotRating > 0
|
||||
? parseFloat((totalBotRatings / filesWithBotRating).toFixed(2))
|
||||
: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +346,9 @@ export class FileRating {
|
||||
|
||||
@Prop({ type: Number, min: 0, max: 5 })
|
||||
guiltyVehicleIdentification: number;
|
||||
|
||||
@Prop({ type: Number, min: 0, max: 5 })
|
||||
botRating: number;
|
||||
}
|
||||
|
||||
// TODO clean all sub Object to other files
|
||||
|
||||
Reference in New Issue
Block a user