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 })
|
@Prop({ type: Number, min: 0, max: 5 })
|
||||||
guiltyVehicleIdentification: number;
|
guiltyVehicleIdentification: number;
|
||||||
|
|
||||||
|
@Prop({ type: Number, min: 0, max: 5 })
|
||||||
|
botRating: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PriceDrop {
|
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" })
|
@ApiParam({ name: "expertId" })
|
||||||
@ApiQuery({ name: "role", enum: ["claim", "blame"] })
|
@ApiQuery({ name: "role", enum: ["claim", "blame"] })
|
||||||
@Get("/:expertId")
|
@Get("/:expertId")
|
||||||
@@ -120,13 +125,28 @@ export class ExpertInsurerController {
|
|||||||
example: 4,
|
example: 4,
|
||||||
description: "تشخیص درست وسیله نقلیه مقصر",
|
description: "تشخیص درست وسیله نقلیه مقصر",
|
||||||
},
|
},
|
||||||
|
botRating: {
|
||||||
|
type: "number",
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 5,
|
||||||
|
example: 4,
|
||||||
|
description: "برای امتیاز دادن به بات",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
required: [
|
required: [
|
||||||
"collisionMethodAccuracy",
|
"collisionMethodAccuracy",
|
||||||
"evaluationTimeliness",
|
"evaluationTimeliness",
|
||||||
"accidentCauseAccuracy",
|
"accidentCauseAccuracy",
|
||||||
"guiltyVehicleIdentification",
|
"guiltyVehicleIdentification",
|
||||||
|
"botRating",
|
||||||
],
|
],
|
||||||
|
example: {
|
||||||
|
collisionMethodAccuracy: 4,
|
||||||
|
evaluationTimeliness: 3,
|
||||||
|
accidentCauseAccuracy: 5,
|
||||||
|
guiltyVehicleIdentification: 4,
|
||||||
|
botRating: 4,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ApiParam({ name: "requestId" })
|
@ApiParam({ name: "requestId" })
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export class ExpertInsurerService {
|
|||||||
|
|
||||||
const insurerValues = insurerRating
|
const insurerValues = insurerRating
|
||||||
? Object.values(insurerRating).filter(
|
? Object.values(insurerRating).filter(
|
||||||
(val): val is number => typeof val === "number" && !isNaN(val),
|
(val): val is number => typeof val === "number" && !isNaN(val),
|
||||||
)
|
)
|
||||||
: [];
|
: [];
|
||||||
const insurerAvg =
|
const insurerAvg =
|
||||||
@@ -768,4 +768,141 @@ export class ExpertInsurerService {
|
|||||||
|
|
||||||
return newBranch;
|
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 })
|
@Prop({ type: Number, min: 0, max: 5 })
|
||||||
guiltyVehicleIdentification: number;
|
guiltyVehicleIdentification: number;
|
||||||
|
|
||||||
|
@Prop({ type: Number, min: 0, max: 5 })
|
||||||
|
botRating: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO clean all sub Object to other files
|
// TODO clean all sub Object to other files
|
||||||
|
|||||||
Reference in New Issue
Block a user